有没有办法用MongoDB原子弹出(删除和检索)随机元素 - 比如Redis的SPOP?
我已经阅读了RandomAttribute tutorial,但现在我需要确保在获取时也删除该元素,这必须以原子方式完成。
我想作为一种替代方案,我可以将数据推送到预先排序的数组字段中,但我真的更愿意让它获取随机记录。
查看$pop
的文档,似乎它不能接受参数,因此它会删除数组的第一个或最后一个元素。
答案 0 :(得分:3)
Mongo中集合中的更新是原子的,因此将findAndModify
与RandomAttribute方法结合起来可以解决这个问题:
var rand = Math.rand();
db.collection.findAndModify({query: {random: {$gte: rand}}, remove: true});
当上述内容返回random: {$lt: rand}
时,请确保同时查询null
。
Protip:有些驱动程序有findAndRemove
,与findAndModify
的{{1}}相同。
答案 1 :(得分:0)
目前基本上没有什么方法可以做你想做的事情。最大的问题是,没有一种原子方法可以按位置删除数组元素。
有关详细信息,请参阅this question。
最好的 - 最接近原子的方式,我可以想到解决这个问题的方法如下。它依赖于你能够在短时间内处理数组中的null元素(这是不是原子的)。
第一步
在客户端生成随机数。使用它来指定要以点表示法删除的数组元素的键(即。" 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
});
(NB。findAndModify
目前默认返回文档更新前,但我读到可能会更改的文件,因此总是使用{{1}指定您想要的内容选项。)
这将保留在数组中选择为new
值的数组元素。
第三步
使用$ pull:
从另一个更新中删除数组中的null元素null
唷!对于您想要做的事情来说,似乎有很多工作要做。我不认识Redis,但SPOP听起来容易多了。无论如何,我希望这有点帮助。它不是单个原子操作,但是(只要你可以处理那些空值)我认为它最重要的部分是。你几乎不会陷入两个不同的线程几乎同时弹出相同元素的情况,我猜测,这是你想要避免的。