Монго запрашивает последнюю версию записей

#arrays #mongodb #sorting #custom-sort

#массивы #mongodb #сортировка #пользовательская сортировка

Вопрос:

Я пытаюсь получить каждую последнюю запись «группы» из Mongo.

Вы можете отображать данные как набор записей вики:

  • Каждую запись можно редактировать (и старые версии сохраняются).
  • Нас интересует последняя версия записей.
  • Записи (и их предки) сортируются по определенной логике.

Чтобы получить более подробную информацию:

  • Каждая запись идентифицируется с помощью itemId
  • Каждый itemId из них может встречаться в наборе данных от 1 до n раз
  • Версии записей сортируются по orderHash

Здесь вы можете увидеть небольшой пакет данных:

 {
    "_id": ObjectId("5f69b963b8705200282d6174"),
    "itemId": "xszy",
    "orderHash": "383u",
    "title": "A",
    "content": "ABC"
},
{
    "_id": ObjectId("5f69b963b8705200282d6175"),
    "itemId": "e92q",
    "orderHash": "5j12",
    "title": "K",
    "content": "KLMN"
},
{
    "_id": ObjectId("5f69b963b8705200282d6178"),
    "itemId": "xszy",
    "orderHash": "p578",
    "title": "A",
    "content": "ABD"
},
{
    "_id": ObjectId("5f69b963b8705200282d6180"),
    "itemId": "mtewy",
    "orderHash": "383u",
    "title": "L",
    "content": "CASE"
},
{
    "_id": ObjectId("5f69b963b8705200282d6189"),
    "itemId": "mtewy",
    "orderHash": "5j12",
    "title": "L1",
    "content": "CASE"
}
  

Я использую следующий агрегированный конвейер для получения желаемого результата:

 db.getCollection('wiki').aggregate([
    {
        // create a sortable field for mongo
        $set: { 
            "sortField": {
                "$indexOfArray": [
                    [ "p578", "5j12", "383u" ], "$orderHash"
                ]
            }
        }
    },
    {
        // sort by created sort field
        "$sort": {
            "sortField": 1 
        }
    },
    {
        // group items by itemId and "save" them sorted in an array
        $group: {
            _id: "$itemId",
            data: {
                $push: "$$ROOT"
            }
        }
    },
    {
        // get first entry of each "group array" to obtain
        // the latest version of each entry
        $project: { 
            resp: { $arrayElemAt: ['$data', 0] }
        } 
    }
])
  

Пока это работает. Но кажется неправильным хранить данные в дополнительном массиве, и я не уверен в производительности (особенно для больших наборов данных с большим количеством изменений). Еще один недостаток заключается в том, что я не просто получаю массив документов обратно, но данные вложены в свойство documents resp (которое не подходит для использования, например, для mongoose).

Есть ли более простое решение для моей проблемы?

РЕШЕНИЕ:

Спасибо Джо (см. Комментарии). Он указал мне на решение.

 db.getCollection('wiki').aggregate([
    {
        $set: { 
            "sortField": {
                "$indexOfArray": [
                    [ "p578", "5j12", "383u" ], "$orderHash"
                ]
            }
        }
    },
    {
        "$sort": {
            "sortField": 1 
        }
    },
    {
        $group: {
            _id: "$itemId",
            resp: {
                $first: "$$ROOT"
            }
        }
    },
    { 
        $replaceRoot: { 
            newRoot: "$resp"
        }
    }
])
  

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

1. Будет ли использовать $first вместо $push того, чтобы получить то, что вы хотите?

2. Да! Это так. Спасибо. Это также экономит один шаг конвейера. Тогда остается только одна проблема.

3. возможно $replaceRoot , этап?

4. Опять же: да! Спасибо!