【发布时间】:2014-07-03 21:01:20
【问题描述】:
在 MongoDB 中,将一个项目添加到数组中并删除任何重复项目的好方法是什么?
如果项目已经在数组中,$addToSet 不会做任何事情。
此SO question 显示了两种前置方式,但不会删除欺骗。
使用 Mongo 2.4.1、MongoMapper 和 Ruby。
【问题讨论】:
标签: ruby mongodb mongodb-query mongomapper
在 MongoDB 中,将一个项目添加到数组中并删除任何重复项目的好方法是什么?
如果项目已经在数组中,$addToSet 不会做任何事情。
此SO question 显示了两种前置方式,但不会删除欺骗。
使用 Mongo 2.4.1、MongoMapper 和 Ruby。
【问题讨论】:
标签: ruby mongodb mongodb-query mongomapper
您可以通过限定您的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}}})
对于 1 的 value 无效,但任何其他值都将添加到 a 数组字段之前。
【讨论】:
$addToSet 运算符当然不会删除现有的重复项,而且作为“集合”的任何元素都不会被认为是有序的,因此无法使用此运算符定位它们。
在任何一种情况下,按照您的逻辑来处理重复项现在都由您来管理。但是,bulk operations API 可以为您提供帮助,而不是拉取文档并在代码中进行操作,这可能会导致并发问题。
因此,为了确保您的逻辑,您将使用 $pull 从您插入的数组中删除任何项目,然后使用 $push,使用需要与 @987654326 耦合的 $position 修饰符@修饰符。
一个基本的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]
【讨论】: