MongoDB:原子弹出随机元素

时间:2011-09-02 04:22:03

标签: mongodb random atomic pop

有没有办法用MongoDB原子弹出(删除和检索)随机元素 - 比如Redis的SPOP

我已经阅读了RandomAttribute tutorial,但现在我需要确保在获取时也删除该元素,这必须以原子方式完成。

我想作为一种替代方案,我可以将数据推送到预先排序的数组字段中,但我真的更愿意让它获取随机记录。

查看$pop的文档,似乎它不能接受参数,因此它会删除数组的第一个或最后一个元素。

2 个答案:

答案 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听起来容易多了。无论如何,我希望这有点帮助。它不是单个原子操作,但是(只要你可以处理那些空值)我认为它最重要的部分是。你几乎不会陷入两个不同的线程几乎同时弹出相同元素的情况,我猜测,这是你想要避免的。