目前基本上没有一个很好的方法来做你想做的事。最大的问题是没有一种原子方法可以按位置删除数组中的元素。
有关更多信息,请参阅this question。
我能想到的最好的 - 最接近原子的 - 解决这个问题的方法如下。它依赖于您能够在短时间内处理数组中的空元素(这不是原子的位)。
第一步
在客户端生成一个随机数。使用它来指定要以点表示法(即“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 听起来要容易得多。无论如何,我希望这会有所帮助。这不是一个单一的原子操作,但(只要你能处理那些空值)我认为它最重要的部分是。你永远不会遇到两个不同的线程几乎同时弹出同一个元素的情况,我猜这就是你要避免的。