#mongodb #mongodb-query
Вопрос:
Я запускаю MongoDB, и у меня возникли проблемы с тем, как создать запрос для фильтрации документов по последней дате каждого отдельного имени и извлечения всего документа.
У меня есть некоторые данные в моей коллекции (студенты):
{ "_id" : ObjectId("61479d4bc146b1663a8f2b7d"), "city" : "SAO PAULO", "name" : "ANA", "status" : "ACTIVE", "date1" : ISODate("2020-09-01T08:14:30.000Z") }
{ "_id" : ObjectId("61479d88c146b1663a8f2b7e"), "city" : "SAO PAULO", "name" : "MARIA", "status" : "ACTIVE", "date1" : ISODate("2020-08-01T04:16:00.000Z") }
{ "_id" : ObjectId("61479dc2c146b1663a8f2b7f"), "city" : "RIO DE JANEIRO", "name" : "MARIA", "status" : "ACTIVE", "date1" : ISODate("2021-02-01T11:10:00.000Z") }
{ "_id" : ObjectId("61479df1c146b1663a8f2b80"), "city" : "SAO PAULO", "name" : "MARIA", "status" : "INACTIVE", "date1" : ISODate("2021-02-01T11:15:00.000Z") }
{ "_id" : ObjectId("61479e60c146b1663a8f2b81"), "city" : "BRASILIA", "name" : "JOHH", "status" : "ACTIVE", "date1" : ISODate("2021-06-01T01:18:00.000Z") }
Я создаю запрос для фильтрации статуса «АКТИВНЫЙ» и показываю только самые последние данные для каждого студента, показывая только «город», «имя», «дату», и я пытаюсь сделать это, используя $MAX или $LAST в ГРУППЕ:
db.getCollection('students').aggregate([
{ $match: { status: "ACTIVE" } },
{ $group: { _id: { name : "$name"},
date1 : { $max : "$date1" } ,
city : { $max : "$city" } } }
])
Желаемый результат:
{ "city" : "SAO PAULO", "name" : "ANA", "date1" : ISODate("2020-09-01T08:14:30.000Z") }
{ "city" : "RIO DE JANEIRO", "name" : "MARIA", "date1" : ISODate("2021-02-01T11:10:00.000Z") }
{ "city" : "BRASILIA", "name" : "JOHH", "date1" : ISODate("2021-06-01T01:18:00.000Z") }
Но в результате получается вот что:
{ "city" : "SAO PAULO", "name" : "ANA", "date1" : ISODate("2020-09-01T08:14:30.000Z") }
{ "city" : "SAO PAULO", "name" : "MARIA", "date1" : ISODate("2021-02-01T11:10:00.000Z") }
{ "city" : "BRASILIA", "name" : "JOHH", "date1" : ISODate("2021-06-01T01:18:00.000Z") }
Он извлекает неправильные данные. Для АНЫ и ДЖОНА (только по одному документу на каждого) все в порядке. Но у МАРИИ есть три документа, и мне нужно извлечь все данные из ее документа с датой $max, и я извлекаю «город» : «САН-ПАУЛУ», а не «город» : «РИО-ДЕ-ЖАНЕЙРО», потому что оператор $MAX применяется и для этого поля. Это применяется ко всем полям, и оператор GROUP не позволяет удалить оператор MAX.
Я не знаю, как это исправить. Как получить весь документ, фильтруя по «последней дате каждого отдельного имени» ?
Ответ №1:
Вы можете использовать этот конвейер агрегации:
- Сначала
$match
, как и у вас. - Затем
$sort
, чтобы получить желаемые значения в первой позиции. Это используется на следующем этапе. - При
$group
агрегировании вы получаете$first
значение (по мере сортировки документа первое значение будет желаемым). - И последнее
$project
, чтобы получить желаемый результат.
db.collection.aggregate([
{
"$match": {
"status": "ACTIVE"
}
},
{
"$sort": {
"date1": -1
}
},
{
"$group": {
"_id": {
"name": "$name"
},
"date1": {
"$first": "$date1"
},
"city": {
"$first": "$city"
}
}
},
{
"$project": {
"_id": 0,
"name": "$_id.name",
"city": 1,
"date1": 1
}
}
])
Пример здесь