Вы не можете атомизировать элементы массива.Но если вы можете реструктурировать свой документ, чтобы использовать объект вместо массива, то это возможно атомарно.Используя вашу нотацию, структура будет
Widget (collection)
--Name
--Properties
--Property1
--Property2
.
:
Пример документа будет
{
name: 'widget-1',
properties: {
'property-1': 100,
'property-2': 200
}
}
Чтобы добавить элемент с именем 'property-3' со значением 300, вы должны сделать
db.widgets.update(
{ name: 'widget-1' },
{ $set: { 'properties.property-3': 300 } }
)
Один недостаток заключается в том, что запрос имен полей (с использованием оператора запроса $exists
) требует сканирования.Вы можете обойти это, добавив дополнительное поле массива, в котором хранятся имена свойств.Это поле может быть проиндексировано и запрошено как обычно.Upserts становятся
db.widgets.update(
{ name: 'widget-1' },
{
$set: { 'properties.property-3': 300 },
$addToSet: { propertyNames: 'property-3' }
}
)
(Имейте в виду, что $addToSet
- это O (n).) При удалении свойства его также необходимо извлечь из массива.
db.widgets.update(
{ name: 'widget-1' },
{
$unset: { 'properties.property-3': true },
$pull: { propertyNames: 'property-3' }
}
)