В коллекции MongoDB, которую я запрашиваю, каждый документ представляет некоторые данные для посылки в определенное время. Каждый раз, когда я получаю обновление для посылки, некоторые поля могут обновляться (ненулевое значение), а некоторые нет (нулевые значения).
Для иллюстрации рассмотрим этот пример. Мы получили 3 набора данных для посылки:
/* 1 */
{
"parcelNum" : "CC123456789FR",
"datetime" : ISODate("2018-09-05T10:48:38.584Z"),
"field1" : "value1_1",
"field2" : "value2_1"
}
/* 2 */
{
"parcelNum" : "CC123456789FR",
"datetime" : ISODate("2018-09-05T10:48:40.566Z"),
"field1" : "value1_2",
"field2" : null
}
/* 3 */
{
"parcelNum" : "CC123456789FR",
"datetime" : ISODate("2018-09-05T10:48:42.777Z"),
"field1" : null,
"field2" : "value2_2"
}
Как извлечь последнее ненулевое значение для всех полей с учетом отметки времени документа, которому они принадлежат?
Используя предыдущий пример, вот что я пытаюсь получить:
{
"parcelNum" : "CC123456789FR",
"field1" : "value1_2",
"field2" : "value2_2"
}
Я пытался выполнить такой запрос, но не могу найти способ смешать значения полей из нескольких документов:
db.testDB.aggregate([
{$sort: { datetime: -1 }},
{$group: { _id: "$parcelNum",
field1: {$first: "$field1" },
field2: {$first: "$field2" }
}}
])
дает мне:
{
"_id" : "CC123456789FR",
"field1" : null,
"field2" : "value2_2"
}
, что неверно, поскольку он использует только значения из самого последнего документа и не смешивает все документы.
Я попробовал другой подход, предложенный Риши в другой теме. Вместо создания нового документа для каждой ревизии он предложил поместить вложенные документы ревизии в массив и сохранить последнюю ревизию в родительском документе.
Примерно так:
{
parcelNum: CC123456789FR,
lastUpdated: ISODate("2018-09-05T10:48:42.777Z")
field1: "value1_2",
field2: "value2_2",
revisions: [
{
datetime: ISODate("2018-09-05T10:48:38.584Z"),
field1: "value1_1",
field2: "value2_1"
},
{
datetime: ISODate("2018-09-05T10:48:40.566Z"),
field1: "value1_2",
field2: null
},
{
datetime: ISODate("2018-09-05T10:48:42.777Z"),
field1: null,
field2: "value2_2"
}
]
}
Однако поддержка последней ревизии не так проста, потому что обновления не принимаются в хронологическом порядке, тогда я могу получить «новый» документ, который имеет более старое значение поля «datetime», и тогда я не должен обновлять поля, кроме случаев, если они нулевые. Затем мне нужно будет записать отметку времени последнего обновления для всех полей, если я хочу это сделать!