Нужна помощь в запросе базы данных Mongo для извлечения данных

#mongodb #mongodb-query

Вопрос:

Учитывая существующую коллекцию базы данных mongo с именем пользователи с некоторыми документами в ней, которая выглядит следующим образом :

 {
    "_id" : ObjectId("611a11a09500700009d09a12"),
    "userId" : "abc",
    "createdAt" : ISODate("2021-08-14T07:22:00.535Z"),
    "isActive" : true,
    "isEligible" : true
},
{
    "_id" : ObjectId("611a11a09500700009d09a13"),
    "userId" : "abc",
    "createdAt" : ISODate("2021-08-15T07:20:00.535Z"),
    "isActive" : true,
    "isEligible" : true
},
{
    "_id" : ObjectId("611a11a09500700009d09a14"),
    "userId" : "def",
    "createdAt" : ISODate("2021-08-15T07:22:00.535Z"),
    "isActive" : true,
    "isEligible" : true
},
{
    "_id" : ObjectId("611a11a09500700009d09a15"),
    "userId" : "abc",
    "createdAt" : ISODate("2021-08-16T07:18:00.535Z"),
    "isActive" : true,
    "isEligible" : true
},
{
    "_id" : ObjectId("611a11a09500700009d09a16"),
    "userId" : "abc",
    "createdAt" : ISODate("2021-08-16T07:20:00.535Z"),
    "isActive" : true,
    "isEligible" : true
}
{
    "_id" : ObjectId("611a11a09500700009d09a17"),
    "userId" : "def",
    "createdAt" : ISODate("2021-08-16T07:22:00.535Z"),
    "isActive" : true,
    "isEligible" : true
}
 

Помимо ключей, упомянутых в каждом из вышеприведенных документов, может быть также несколько других ключей.

Здесь я хочу написать запрос, который выполняет следующие операции и возвращает данные:

  1. Выберите записи с createdAt больше или равно «2021-08-15T00:00:00.000 Z».
  2. Для каждого идентификатора пользователя возвращайте только последнюю запись, т. е. запись, отсортированную по createdAt в порядке убывания.
  3. Возвращаемый документ должен содержать все ключи, которые присутствуют в исходном документе. Количество ключей может быть намного больше, чем указано в документе. Таким образом, запрос должен автоматически возвращать все ключи.

Ниже приведен пример вывода, который требуется:

 {
    "_id" : ObjectId("611a11a09500700009d09a16"),
    "userId" : "abc",
    "createdAt" : ISODate("2021-08-16T07:20:00.535Z"),
    "isActive" : true,
    "isEligible" : true
}
{
    "_id" : ObjectId("611a11a09500700009d09a17"),
    "userId" : "def",
    "createdAt" : ISODate("2021-08-16T07:22:00.535Z"),
    "isActive" : true,
    "isEligible" : true
}
 

Ответ №1:

Вы можете использовать этот этап агрегирования:

  • Сначала $match нужно получить только те документы, дата которых больше или равна желаемой дате.
  • Затем $sort установить значения первой позиции в порядке убывания.
  • И последнее $group , userId получив только первое значение (в соответствии с порядком -1 , первое значение будет в соответствии с desc порядком)
 db.collection.aggregate([
  {
    "$match": {
      "createdAt": {
        "$gte": ISODate("2021-08-15T00:00:00.000Z")
      }
    }
  },
  {
    "$sort": {
      "createdAt": -1
    }
  },
  {
    "$group": {
      "_id": "$userId",
      "createdAt": {
        "$first": "$createdAt"
      }
    }
  }
])
 

Пример здесь

Кроме того, если ObjectId для вас важен конечный результат, вы также можете добавить один такой этап.

Комментарии:

1. Спасибо за ответ. Просто обновление, в вашем ответе нам нужно упомянуть все ключи, которые нам нужно вернуть в операторе «$project» вручную. Но я хочу, чтобы запрос автоматически возвращал все ключи, так как количество ключей может быть большим. Я также обновил вопрос более четкими инструкциями и был бы признателен, если бы вы могли предоставить обновленную информацию о решении для того же самого.

2. Ты имеешь в виду что-то вроде этого . Обратите внимание, что я добавил новое значение newValue , которое отображается, если оно существует, в противном случае будет равно нулю. Но вы должны вручную добавить все параметры в $project или альтернативно задать значения в data поле, подобное этому .

3. С тех пор как нет. количество ключей может быть большим, было бы сложно добавить все параметры в $project вручную, я бы хотел, чтобы запрос группировал данные по идентификатору пользователя и выбирал последнюю запись для каждого идентификатора пользователя и возвращал все ключи для последней записи, как показано в примере ответа.

4. Затем вы можете использовать этот запрос с помощью $replaceRoot . Если это сработает для вас, я могу отредактировать свой ответ.

5. Упомянутый вами запрос, в котором используется $replaceRoot, возвращает результат в том же формате, что и желаемый. Но он не поддерживает порядок сортировки в createdAt. Когда я запускал запрос несколько раз, записи не сортировались в порядке убывания createdAt. Вы можете увидеть то же самое на mongoplayground.net/p/Q4A0UJ_E4u2