如何在Mongo中添加数组并删除dupes?

时间:2014-07-03 21:01:21

标签: ruby mongodb mongodb-query mongomapper

在MongoDB中,将项目添加到数组并删除任何重复项目的好方法是什么?

如果项目已经在数组中,则

$addToSet不会执行任何操作。

这个SO question显示了两种前置方式,但不会删除欺骗。

使用Mongo 2.4.1,MongoMapper和Ruby。

2 个答案:

答案 0 :(得分:1)

您可以通过限定update条件来实现此目的,以包括前置值不在数组中。然后将$push$each$position一起使用,您可以在数组的开头插入该项,只要该数组尚未存在于数组中。

假设文档看起来像:

{
  "_id": 1,
  "a": [1]
}

您可以在shell中执行更新:

var value = 1;
db.test.update(
    {_id: 1, a: {$ne: value}}, 
    {$push: {a: {$each: [value], $position: 0}}})

对于value为1的情况没有效果,但任何其他值都将添加到a数组字段之前。

答案 1 :(得分:1)

$addToSet运算符当然不会删除现有的重复项,也不会删除" set"是任何被认为是有序的元素,因此无法用这个算子来定位它们。

在任何一种情况下,按照你的逻辑来处理重复项现在由你来管理。但是bulk operations API可以帮助你,而不是拉动文档并在代码中操作,这可能会导致并发问题。

因此,为了确保您的逻辑,您可以使用$pull从您插入的数组中删除任何项目,然后使用$push,使用需要的$position修饰符与$each修饰符结合使用。

一个基本的mongomapper代码示例:

require 'mongo_mapper'
require 'pp'

MongoMapper.database = 'test'

class User
  include MongoMapper::Document

  key :array, Array
end
User.collection.remove

user = User.create(:array => [5, 4, 4, 6])

pp user

bulk = User.collection.initialize_unordered_bulk_op

bulk.find(:_id => user._id, :array => 4)
  .update_one({ "$pull" => { "array" => 4 }})

bulk.find({"_id" => user._id, "array" => { "$ne" => 4 }})
  .update_one({
    "$push" => {
      "array" => { "$each" => [4], "$position" => 0 }
    }
  })

res = bulk.execute()

pp res

pp user.reload

严格地说,这仍然不是原子操作,而是在多次更新中执行。但API实现确实通过线路将这两个请求一起发送,并连续实现它们。因此,这与您目前将获得逻辑的原子操作非常接近。

此示例中的结果数组当然是:

array: [4, 5, 6]