Сортировка из массива вложенных объектов MongoDB — NodeJS

#node.js #mongodb #mongoose

#node.js #MongoDB #мангуст

Вопрос:

надеюсь, у вас все хорошо, и всех с Новым годом. Надеюсь, что в конечном итоге это будет лучше, чем 2020 X). Здесь я столкнулся с проблемой, которую пока не могу найти решение. Вот пример модели данных MongoDB :

 `{ "_id" : ObjectId("5fe715bf43c3ca0009503f1d"), 
"firstname" : "Nicolas ",
"lastname" : "Mazzoleni",
"email" : "nicolas.mazzoleni@orange.fr",
"items" : [ 
    {
        "item" : ObjectId("5f6c5422eeaa1364b0d7b267"),
        "createdAt" : "2020-12-26T10:51:43.685Z"
    }, 
    {
        "item" : ObjectId("5f6c5422eeaa1364b0d7b270"),
        "createdAt" : "2021-01-04T09:21:46.260Z"
    }
],
"createdAt" : ISODate("2020-12-26T10:51:43.686Z"),
"updatedAt" : ISODate("2021-01-04T09:21:46.260Z"),
"__v" : 0
}`
 

Давайте предположим, что у меня много строк, подобных приведенной выше, с разными датами «items.createdAt».

В конце цель состоит в том, чтобы выполнить запрос, который найдет элемент, в котором идентификатор объекта равен тому, что я ищу, и отсортировать по соответствующей дате «items.createdAt». Вот запрос, который я использую в данный момент, который не сортирует по соответствующему вложенному объекту :

   `const items = await repo
  .find({ 'items.item': ObjectId("5f6c5422eeaa1364b0d7b270") })
  .sort({ 'items.createdAt': -1 })
  .limit(5)`
 

PS: я также пытался использовать агрегации, которые заканчивались этим запросом

   `const items = await repo.aggregate([
  { $unwind: '$items' },
  { $match: { 'items.item': ObjectId("5f6c5422eeaa1364b0d7b270") } },
  { $sort: { 'items.createdAt': -1 } },
  { $limit: 5 },
])`
 

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

Спасибо за вашу помощь! Николас

Ответ №1:

К сожалению, MongoDB не может сортировать вложенный массив с помощью простого запроса. Для этого вам нужно использовать aggregate.

 
db.collection.aggregate([
  {
    "$match": {
      "items.item": ObjectId("5f6c5422eeaa1364b0d7b270")
    }
  },
  {
    "$unwind": "$items"
  },
  {
    "$sort": {
        "items.createdAt": -1
     }
  },
  { "$limit" : 5 },
  {
    "$group": {
        "items": {
            "$push": "$items"
        },
        "_id": 1
  }
])
 

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

1. Эй, @JustRaman, спасибо за быстрый ответ. Итак, если aggregate является единственным решением, есть ли у вас способ сделать этот запрос с использованием индексов? Потому что база данных, лежащая в основе, содержит миллионы записей. Спасибо 🙏🏼

2. Aggregate будет использовать любые индексы, если не существует специального способа. кроме этого.