Найти между двумя диапазонами дат строки в весенний mongodb - PullRequest
2 голосов
/ 14 февраля 2020

У меня есть документ Person как

{
  "_id": {
    "$oid": "5e44659dcd"
  },
  "record": {
    "Date_Of_Birth": "9/25/2018"
  },
  "_class": "com.example.entities.Birth"
}

Record имеет тип object, Date_Of_Birth имеет тип String, но Date хранится в нем, и я хочу выполнить запрос, чтобы использовать над этим операции $ gte и $ lte. Я использую данные весны mongodb. Кажется, сначала я должен использовать $ dateFromString, чтобы преобразовать его в дату, но, похоже, это агрегация, которая, я думаю, мне не нужна.

Ниже приведен код, который я создал до сих пор

Pageable pageable = PageRequest.of(page, size);
Query query = new Query(
        Criteria
                .where("record.Date_Of_Birth").gte(DateOperators.dateFromString(startDate).withFormat("mm/dd/yyyy"))
                .andOperator(Criteria.where("record.Date_Of_Birth").lte(DateOperators.dateFromString(endDate).withFormat("mm/dd/yyyy"))
)).with(pageable);

, который генерирует этот запрос

{ "record.Date_Of_Birth" : { "$gte" : { "value" : { "dateString" : "9/25/2018", "format" : "mm/dd/yyyy"}}}, "$and" : [{ "record.Date_Of_Birth" : { "$lte" : { "value" : { "dateString" : "9/25/2018", "format" : "mm/dd/yyyy"}}}}]}

и вообще не работает. Есть идеи?

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

$ expr разрешает использование операторов агрегирования внутри запроса. Это позволит вам преобразовать сохраненное значение в дату, чтобы вы могли сравнить яблоки с яблоками.

db.collection.find({
  $expr: {
    $gte: [
      {$dateFromString: {
           dateString: "$record.Date_Of_Birth", 
           format: "%m/%d/%Y", 
           timeZone: "EST5EDT"}},
      {$dateFromString: {
           dateString: "9/25/2018", 
           format: "%m/%d/%Y", 
           timeZone: "EST5EDT"}}
    ]
  }
})
0 голосов
/ 15 февраля 2020

Поскольку формат даты для поля документа Date_Of_Birth и вводимые даты в строковых данных и отформатированы как "MM / dd / yyyy", сравнение не будет правильным, если используется как они есть. Существуют различные способы решения этой проблемы.

Преобразование обоих форматов даты в строки "гггг / мм / дд", сравнение или , преобразование обеих дат в Date объектов и сравнение. Обратите внимание, что в примере кода показано использование значений даты, преобразованных в Date объекты.

Чтобы преобразовать даты для запроса find, фильтр будет использовать оператор агрегирования даты или преобразования строк. Фильтр запросов find может использовать операторы агрегации только с оператором * 1014. *

Я не могу понять, ясно ли использовать $expr с API-интерфейсами Spring-Data MongoDB (я подозреваю, что такого API для обработки не существует $expr, но для этого может существовать обходной путь).

Чтобы четко выполнить запрос, используйте агрегацию. Ниже приведены версии Mon go Shell и Spring Data.

db.persons.aggregate( [ 
  { 
      $addFields: { 
          matches: { 
              $and: [ 
                  { $gte: [ 
                      { $dateFromString: { dateString: "$record.Date_Of_Birth", format: "%m/%d/%Y" } },  
                       ISODate("2018-09-24T00:00:00.00Z") // input from date
                   ] },
                 { $lte: [ 
                     { $dateFromString: { dateString: "$record.Date_Of_Birth", format: "%m/%d/%Y" } }, 
                      ISODate("2018-11-10T00:00:00.00Z") // input to date
                 ] }
              ]
          }
      }
  },
  { 
      $match: { matches: true } 
  }
] )


Spring-Data Java код:

// Convert the String input dates to Date objects to be used in the query
String from = "9/24/2018";
String to = "11/10/2018";
DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
Date fromDt = dateFormat.parse(from);
Date toDt = dateFormat.parse(to);

// Build and run the query
MongoOperations mongoOps = new MongoTemplate(MongoClients.create(), "test");
Aggregation agg = newAggregation(
    project("record.Date_Of_Birth")
        .and(Gte.valueOf(DateOperators.DateFromString.fromStringOf("record.Date_Of_Birth").withFormat("%m/%d/%Y")) 
            .greaterThanEqualToValue(fromDt))
                .as("matches1")
        .and(Lte.valueOf(DateOperators.DateFromString.fromStringOf("record.Date_Of_Birth").withFormat("%m/%d/%Y")) 
            .lessThanEqualToValue(toDt))
              .as("matches2"),
    match(where("matches1").is(true)),
    match(where("matches2").is(true))
);

AggregationResults<Person> results = mongoOps.aggregate(agg, "persons", Person.class);
results.forEach(System.out::println);
...