Вы можете попробовать выполнить агрегацию ниже.
Проецировать ключевое поле из поля типа, отсортировать по updatedAt и group, чтобы выбрать последнее значение и сохранить ссылку и updatedAt. * 1003 *
Группировать все документы и объедините различные значения ключа и сохраните updatedAt и постобработку для форматирования документа.
Выполните поиск, чтобы получить пользовательское значение, а затем замените Root, чтобы объединить основной документ с документом поиска.
Сортировка документов по имени.
db.collectionname.aggregate([
{"$addFields":{"key":{"$arrayElemAt":[{"$split":["$type","-"]},1]}}},
{"$sort":{"updatedAt":-1}},
{"$group":{
"_id":{"referenceId":"$referenceId","key:"$key"},
"value":{"$first":"$$ROOT"},
"referenceId":{"$first":"$referenceId"},
"updatedAt":{"$first":"$updatedAt"}
}},
{"$sort":{"updatedAt":-1}},
{"$group":{
"_id":"$_id.referenceId",
"data":{
"$mergeObjects":{"$arrayToObject":[[["$_id.key","$value"]]]}
},
"updatedAt":{"$first":"$updatedAt"}
}},
{"$addFields":{
"data.referenceId":"$referenceId",
"data.updatedAt":"$updatedAt"
}},
{"$project":{"data":1}},
{"$lookup":{
"from":"othercollectionname",
"localField":"data.referenceId",
"foreignField":"_id",
"as":"reference"
}},
{"$replaceRoot":{
"newRoot":{
"$mergeObjects":[{"$arrayElemAt":["$reference",0]},"$data"]}
}},
{"$project":{"_id":0}},
{"$sort":{"name":1}}
])
Альтернативный подход:
При всех преобразованиях ваш запрос будет немного медленнее. Вы можете сделать несколько настроек.
Ввод
{
_id: "<random>"
type: "user",
key: "name"
referenceId: "u12345"
value: "John Doe Boy"
updatedAt: 1584450565
}
Запрос
db.collectionname.aggregate([
{"$sort":{"updatedAt":-1}},
{"$group":{
"_id":{"referenceId":"$referenceId","key":"$key"},
"top":{"$first":"$$ROOT"}
}},
{"$sort":{"top.updatedAt":-1}},
{"$group":{
"_id":"$_id.referenceId",
"max":{"$max":{"$cond":[{"$eq":["$key", "name"]},"$top.value",null]}},
"key-values":{"$push":{"k":"$_id.key","v":"$top.value"}},
"updatedAt":{"$first":"$top.updatedAt"}
}},
{"$lookup":{
"from":"othercollectionname",
"localField":"_id",
"foreignField":"_id",
"as":"reference"
}},
{"$project":{"_id":0}},
{"$sort":{"max":1}}
])
Мы можем еще больше уточнить нашу схему, чтобы удалить несколько других этапов. Мы уверены, что мы добавляем последнее значение в конце массива. Что-то вроде
Ввод
{
_id: "<random>"
type: "user",
key: "name"
referenceId: "u12345"
updates:[
{"value": "John Doe Boy", updatedAt: 1584450565},
{"value": "John Doe", updatedAt: 1584450566}
]
}
Запрос
db.collectionname.aggregate([
{"$addFields":{"latest":{"$arrayElemAt":["$updates",-1]}}},
{"$group":{
"_id":"$referenceId",
"max":{"$max":{"$cond":[{"$eq":["$key", "name"]},"$latest.value",null]}},
"updatedAt":{"$first":"$updatedAt"}
"key-values":{"$push":{"k":"$key","v":"$latest.value"}},
"updatedAt":{"$first":"$latest.updatedAt"}
}},
{"$lookup":{
"from":"othercollectionname",
"localField":"_id",
"foreignField":"_id",
"as":"reference"
}},
{"$project":{"_id":0}},
{"$sort":{"max":1}}
])