Mongodb 如何原子化地弹出随机元素?

Mongodb 如何原子化地弹出随机元素?,mongodb,random,atomic,Mongodb,Random,Atomic,有没有一种方法可以用MongoDB-like Redis自动弹出(删除和检索)一个随机元素 我已经阅读了,但是现在我需要确保元素在获取时也被删除,这必须以原子方式完成 我想作为一种替代方法,我可以将数据推送到预先排序的数组字段中,但我更愿意让它获取一条随机记录 查看$pop的文档,它似乎不能接受参数,因此它要么删除数组的第一个元素,要么删除数组的最后一个元素。目前基本上没有一种很好的方法来执行您想要执行的操作。最大的问题是,没有一种原子方法可以根据数组元素的位置删除它 有关此操作的更多信息,请参

有没有一种方法可以用MongoDB-like Redis自动弹出(删除和检索)一个随机元素

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

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


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

目前基本上没有一种很好的方法来执行您想要执行的操作。最大的问题是,没有一种原子方法可以根据数组元素的位置删除它

有关此操作的更多信息,请参阅

下面是我能想到的解决这个问题的最好的、最接近原子的方法。它依赖于您能够在短时间内处理数组中的空元素(这是非原子的位)

第一步

在客户端生成一个随机数。使用此选项可以指定要在点表示法(即“my_array.4”)中删除的数组元素的键,因为这不能在查询中动态完成

第二步

在使用
find和modify
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,通过另一次更新从数组中删除null元素:

db.mycollection.update({_id: 1}, {$pull: {my_array: null}})

呸!似乎有很多工作要做。我不知道Redis,但SPOP听起来容易多了。无论如何,我希望这能有所帮助。它不是一个单一的原子操作,但是(只要你能处理这些空值),我认为它最重要的部分是。你永远不会遇到两个不同的线程几乎同时弹出同一个元素的情况,我猜,这是你试图避免的。Mongo中集合中的更新是原子性的,因此将
findAndModify
与RandomAttribute方法相结合可以做到:

var rand = Math.rand();
db.collection.findAndModify({query: {random: {$gte: rand}}, remove: true});
只要确保在上面返回
null
时也查询
random:{$lt:rand}


Protip:一些驱动程序有
findAndRemove
,这与
findandremify
remove:true

相同,我同时偶然发现findandremify,并将其与随机属性方法结合使用。它类似于db.items.findAndModify({query:{random:{$gte:rand}},remove:true})。