Кто-нибудь знает, как добавить элемент массива в массив mongodb и установить «виртуальный» порядок размера массива, и все это за атомарную операцию?
Итак, что-то вроде:
db.users.updateOne(
{ _id: 1},
{ $addToSet: { images: {name: 'new image', order: "size of the array"} } }
)
Идея состоит в том, чтобы последний добавленный элемент массива всегда имел последний порядок.
Обновлять:
Данные до операции:
{
_id: 1,
images: [
{ name: 'some name', order: 0 }
]
}
Данные после операции:
{
_id: 1,
images: [
{ name: 'some name', order: 0 },
{ name: 'new image', order: 1 }
]
}
Обновление 2:
Если кому-то интересно, чтобы обновить порядок атомарно, вы можете сделать что-то вроде этого (конечно, построить это динамически):
db.collection.update({
_id: 1
},
{
$set: {
"images.$[elem].order": 4,
"images.$[elem2].order": 3
}
},
{
arrayFilters: [
{
"elem.name": {
$eq: "some name"
}
},
{
"elem2.name": {
$eq: "new image"
}
}
]
})
Спасибо!
🤔 А знаете ли вы, что...
MongoDB поддерживает шардирование данных для распределения нагрузки и хранения больших наборов данных...
Предполагая, что ваше поле order
будет целочисленным, вы можете использовать $let
для вычисления следующего номера заказа и использовать $concatArrays
для добавления его в конец массива.
Некоторые сценарии:
images
уже содержит данные: $max
получит наибольшее order
число, $add
1 к нему.images
— пустой массив: результат $max
вернется к 0 из-за $ifNull
images.order
не является совершенно 0-м упорядоченным: между ним могут быть пробелы или он не начинается с 0. Он будет обрабатываться $max
и $add
1 логикой.images
является пустым полем или не существует: оно будет защищено $ifNull
и вернется к пустому массиву.db.collection.update({},
[
{
"$set": {
"images": {
"$let": {
"vars": {
"seq": {
"$ifNull": [
{
"$add": [
{
"$max": "$images.order"
},
1
]
},
0
]
}
},
in: {
"$concatArrays": [
{
"$ifNull": [
"$images",
[]
]
},
[
//your payload here
{
"name": "new image",
"order": "$$seq"
}
]
]
}
}
}
}
}
],
{
multi: true
})
Обратите внимание, что вы уже храните детали изображения в массиве, поэтому их порядок уже определяется позицией в массиве. Таким образом, если мотивом использования атрибута order
является запрос индекса массива позже, есть и другие способы сделать это, и это может быть избыточно.
Например, оператор $unwind опционально возвращает индекс массива. Вы можете запросить это вместо настраиваемого поля, которое необходимо поддерживать отдельно каждый раз при обновлении поля images
.