#arrays #mongodb #mongoose #mongodb-query
#массивы #mongodb #mongoose #mongodb-запрос
Вопрос:
Я хочу удалить элементы ($ unset) из моих объектов MongoDB с условием, если у того же объекта есть аналогичный элемент. Мой объект:
{
"_id": "5eabf8b144345b36b00bfbaa",
"ranktime": [{
"pos":"2",
"datum":"Mon May 05 2020 12:22:52 GMT 0200 (GMT 02:00)",
"source":"SOURCE2"
},{
"pos":"1",
"datum":"Fri May 01 2020 12:23:10 GMT 0200 (GMT 02:00)",
"source":"SOURCE1"
},{
"pos":"37",
"datum":"Fri May 01 2020 12:25:14 GMT 0200 (GMT 02:00)",
"source":"SOURCE2"
},{
"pos":"12",
"datum":"Fri May 01 2020 12:25:14 GMT 0200 (GMT 02:00)",
"source":"SOURCE2"
},{
"pos":"37",
"datum":"Fri May 01 2020 18:45:27 GMT 0200 (GMT 02:00)",
"source":"SOURCE2"
}]
}
Итак, я хочу удалить запись в, ranktime
если ranktime.source == "SOURCE2"
и если дата такая же, как с предыдущим объектом. На самом деле мне приходится перебирать отдельные элементы ranktime
. Возможно ли это в MongoDB?
Ожидаемый результат был бы:
{
"_id": "5eabf8b144345b36b00bfbaa",
"ranktime": [{
"pos":"2",
"datum":"Mon May 05 2020 12:22:52 GMT 0200 (GMT 02:00)",
"source":"SOURCE2"
},{
"pos":"1",
"datum":"Fri May 01 2020 12:23:10 GMT 0200 (GMT 02:00)",
"source":"SOURCE1"
},{
"pos":"37",
"datum":"Fri May 01 2020 12:25:14 GMT 0200 (GMT 02:00)",
"source":"SOURCE2"
}]
}
Комментарии:
1. Какая у вас версия MongoDB? И почему был удален последний (уникальная дата)
2. Моя версия 4.2.8 и, извините, я имею в виду только ту же дату (День), игнорируя время. Вот почему удаляется последний
Ответ №1:
В принципе, вы можете использовать $reduce для обработки массива и определения предыдущего элемента с помощью операторов $let и $arrayElemAt. Новый синтаксис $set позволяет использовать агрегацию в инструкции update:
db.col.updateMany({}, [
{
$set: {
ranktime: {
$reduce: {
input: "$ranktime",
initialValue: [],
in: {
$let: {
vars: { last: { $arrayElemAt: [ "$$value", -1 ] } },
in: {
$cond: [
{
$and: [
{ "$eq": [ "$$last.source", "SOURCE2" ] },
{ "$eq": [ { $substr: [ "$$last.datum", 0, 15 ] }, { $substr: [ "$$this.datum", 0, 15 ] } ] },
]
},
"$$value",
{ $concatArrays: [ "$$value", [ "$$this" ] ] }
]
}
}
}
}
}
}
}
])
Комментарии:
1. большое вам спасибо! Это потрясающе. У меня просто другая проблема. Можно ли рассматривать не только последний элемент, но и все элементы в массиве? Может случиться так, что идентичные объекты не сохраняются один за другим. Есть ли у вас какие-либо рекомендации для этого случая? Спасибо!
2. @AlexanderRiedel вы все еще можете использовать тот же подход и ссылаться на
$$value
который содержит все предыдущие значения или$ranktime
ссылаться на все из них3. Хорошо, насколько я понимаю, вместо
$arrayElemAt: [ "$$value", -1 ]
я должен, я должен предоставить весь массив. Но настройкаvars: { last: "$ranktime }
не работает. Есть ли какая-либо документация об$$value
переменной в MongoDB? Это не определено в$let
инструкции, но в документации для$let
говорится, что вы можете использовать только определенные переменные, и, похоже, это также не системная переменная? Спасибо!4.
$$value
является результатом предыдущей итерации $reduce, поэтому изначально это будет пустой массив, а затем он будет содержать произведение$concatArrays
5. хорошо, значит, тогда должна сработать ссылка на
$ranktime
(которая имеет все значения) вместо только$$value
, но я почему-то чего-то не хватает? mongoplayground.net/p/xzOFbfz3Zsa изменение находится в строке 13