В принципе, в настоящее время нет хорошего способа сделать то, что вы хотите.Большая проблема в том, что не существует атомарного способа удалить элемент массива по его позиции.
См. этот вопрос для получения дополнительной информации по этому вопросу.
Лучший способ - ближайший к атомарному - обойти это можно следующим образом.Он полагается на то, что вы сможете обрабатывать нулевые элементы в массиве в течение короткого времени (это не атомарный бит).
Шаг первый
Генерироватьслучайное число на стороне клиента.Используйте это, чтобы указать ключ элемента массива, который вы хотите удалить в точечной нотации (т. Е. «My_array.4»), поскольку AFAIK это не может быть сделано динамически в запросе.
Шаг второй
Использование случайного числа для атомарного сброса выбранного элемента массива при извлечении его, как это было до обновления с использованием findAndModify
с new
установленным в false.Предполагая, что сгенерированное вами случайное число было 4
, вы должны сделать что-то вроде следующего:
db.mycollection.findAndModify({
query: {_id: 1},
update: {$unset: {"my_array.4" : true }},
fields: {my_array : {$slice : [4, 1]}, _id : false},
new: false
});
(Примечание: findAndModify
в настоящее время возвращает документ, предварительно обновленный по умолчанию, но я где-то читал, чтоэто может измениться, поэтому рекомендуется всегда указывать, что вы хотите, используя опцию new
.)
Это оставит элемент массива, который был выбран как значение null
в массиве.
Шаг третий
Удалите нулевой элемент из массива с помощью другого обновления, используя $ pull:
db.mycollection.update({_id: 1}, {$pull: {my_array: null}})
Фу!Похоже, много работы для того, что вы хотите сделать.Я не знаю Redis, но SPOP звучит намного проще.Я надеюсь, что это все равно немного помогает.Это не единственная атомарная операция, но (пока вы можете обрабатывать эти нули), я думаю, что наиболее важными ее частями являются.Вы никогда не попадете в ситуацию, когда два разных потока выталкивают один и тот же элемент практически в одно и то же время, чего, я полагаю, вы пытаетесь избежать.