#mongodb #mongodb-query
Вопрос:
У меня есть такой документ в MongoDB:
{
"name": "wine",
"foodstuffSelectedPortions": {
"id_1": [
{
"foodstuffId": "f1",
"portion": {
"portionName": "portion name 1",
"portionWeight": {
"value": 1,
"unit": "KG"
}
}
},
{
"foodstuffId": "f2",
"portion": {
"portionName": "portion name 2",
"portionWeight": {
"value": 100,
"unit": "ML"
}
}
}
],
"id_2": [
{
"foodstuffId": "f3",
"portion": {
"portionName": "portion name 3",
"portionWeight": {
"value": 15,
"unit": "ML"
}
}
}
]
}
}
и я хочу обновить foodstuffSelectedPortions.portion
объект в массив, содержащий этот объект. Таким образом, ожидаемый результат должен выглядеть следующим образом:
{
"name": "wine",
"foodstuffSelectedPortions": {
"id_1": [
{
"foodstuffId": "f1",
"portion": [
{
"portionName": "portion name 1",
"portionWeight": {
"value": 1,
"unit": "KG"
}
}
]
},
{
"foodstuffId": "f2",
"portion": [
{
"portionName": "portion name 2",
"portionWeight": {
"value": 100,
"unit": "ML"
}
}
]
}
],
"id_2": [
{
"foodstuffId": "f3",
"portion": [
{
"portionName": "portion name 3",
"portionWeight": {
"value": 15,
"unit": "ML"
}
}
]
}
]
}
}
Я пробовал этот запрос:
db.foodstuff.update(
{ },
{ $set: { "foodstuffSelectedPortions.$[].portion": ["$foodstuffSelectedPortions.$[].portion"] } }
)
но это выдает мне ошибку: Cannot apply array updates to non-array element foodstuffSelectedPortions:
которая выглядит нормально, потому foodstuffSelectedPortions
что это объект, а не массив.
Как правильно написать этот запрос? Я использую MongoDB 4.4.4 и оболочку Mongo.
Комментарии:
1. id_1 , id_2, я думаю, не знают схемы, верно? это данные, и у вас может быть их неизвестное количество? например, id_25 и т. Д. Или у вас всегда есть ровно 2 с именами id_1 и id_2 ? Если вы храните данные о ключах, я думаю, что лучше всего изменить вашу схему на что-то вроде этого , если часть будет содержать более 1 элемента, затем создайте массив документов «часть», в противном случае документ подойдет. Подумайте об этом, исходя из ваших потребностей.
2. Хорошо, я согласен с изменением схемы, как вы описали, но для этого мне нужен запрос, потому что у меня много данных, и изменение вручную-это не вариант.
Ответ №1:
Запрос (тот, который вы задали)
(сделайте updateMany, чтобы обновить все до новой схемы)
- преобразуется в массив
- карта на массиве
- сопоставьте вложенный массив, заменив объект части массивом
db.collection.update({},
[
{
"$set": {
"foodstuffSelectedPortions": {
"$arrayToObject": {
"$map": {
"input": {
"$objectToArray": "$foodstuffSelectedPortions"
},
"in": {
"k": "$f.k",
"v": {
"$map": {
"input": "$f.v",
"in": {
"$mergeObjects": [
"$f1",
{
"portion": [
"$f1.portion"
]
}
]
},
"as": "f1"
}
}
},
"as": "f"
}
}
}
}
}
])
Запрос
(альтернативная схема с 2 уровнями вложенности вместо 3 и без данных о ключах)
Примером того, почему данные о ключах плохие(я думаю, есть исключения), является то, почему вы застряли, вы хотели обновить все, но вы не знали их имен, поэтому не могли их выбрать. Если бы они были у вас в массиве, вы могли бы создать карту для всех или использовать оператор обновления для обновления всех элементов массива (например, как вы пытались это сделать и пожаловались, что это объект).
*Но не используйте эту схему, если она лучше не соответствует вашим данным и вашим запросам.
db.collection.update({},
[
{
"$set": {
"foodstuffSelectedPortions": {
"$reduce": {
"input": {
"$objectToArray": "$foodstuffSelectedPortions"
},
"initialValue": [],
"in": {
"$let": {
"vars": {
"f": "$this"
},
"in": {
"$concatArrays": [
"$value",
{
"$map": {
"input": "$f.v",
"in": {
"$mergeObjects": [
"$f1",
{
"name": "$f.k",
"portion": [
"$f1.portion"
]
}
]
},
"as": "f1"
}
}
]
}
}
}
}
}
}
}
])
Для обновления конвейера требуется MongoDB >=4.2