【问题标题】:How to atomically pop random element?如何原子地弹出随机元素?
【发布时间】:2011-11-08 21:39:24
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: mongodb random atomic


    【解决方案1】:

    Mongo 中集合内的更新是原子的,因此将 findAndModify 与 RandomAttribute 方法结合使用就可以了:

    var rand = Math.rand();
    db.collection.findAndModify({query: {random: {$gte: rand}}, remove: true});
    

    只要确保在上面返回null时也查询random: {$lt: rand}

    Protip:一些驱动程序有findAndRemove,这与findAndModifyremove: true 相同。

    【讨论】:

      【解决方案2】:

      目前基本上没有一个很好的方法来做你想做的事。最大的问题是没有一种原子方法可以按位置删除数组中的元素。

      有关更多信息,请参阅this question

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

      第一步

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

      第二步

      使用随机数以原子方式取消设置数组的选定元素,同时使用findAndModifynew 设置为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 听起来要容易得多。无论如何,我希望这会有所帮助。这不是一个单一的原子操作,但(只要你能处理那些空值)我认为它最重要的部分是。你永远不会遇到两个不同的线程几乎同时弹出同一个元素的情况,我猜这就是你要避免的。

      【讨论】:

      • 同时我偶然发现了 findAndModify,我将它与 RandomAttribute 方法结合使用。类似于 db.items.findAndModify({query: {random: {$gte: rand}}, remove: true})。
      猜你喜欢
      • 2023-03-11
      • 2019-08-25
      • 1970-01-01
      • 2017-08-03
      • 1970-01-01
      • 2010-09-14
      • 1970-01-01
      • 2021-09-12
      • 2018-03-28
      相关资源
      最近更新 更多