使用MongoDb升级多个记录

我试图让MongoDB使用以下查询来追加多个记录,最终使用MongoMapper和Mongo ruby​​驱动程序。

db.foo.update({event_id: { $in: [1,2]}}, {$inc: {visit:1}}, true, true) 

如果存在所有记录,则此方法可以正常工作,但不会为不存在的记录创建新记录。 以下命令具有shell所需的效果,但从ruby驱动程序可能并不理想。

 [1,2].forEach(function(id) {db.foo.update({event_id: id}, {$inc: {visit:1}}, true, true) }); 

我可以循环遍历我想要在ruby中插入的每个id,但这样就需要为每个项目访问数据库。 有没有办法从ruby驱动程序中只有一次数据库中的多个项目? 这里的最佳做法是什么? 使用mongomapper和ruby驱动程序,有没有办法在一个批处理中发送多个更新,生成如下所示的内容?

 db.foo.update({event_id: 1}, {$inc: {visit:1}}, true); db.foo.update({event_id: 2}, {$inc: {visit:1}}, true); 

样本数据:

如果存在两条记录,则命令后的所需数据。

 { "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 11 } { "_id" : ObjectId("4d6baf56c0d8bb8238d0209a"), "event_id" : 2, "visit" : 2 } 

如果存在两条记录,则命令后的实际数据

 { "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 11 } { "_id" : ObjectId("4d6baf56c0d8bb8238d0209a"), "event_id" : 2, "visit" : 2 } 

如果仅存在具有event_id 1的记录,则命令后的所需数据。

 { "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 2 } { "_id" : ObjectId("4d6baf56c0d8bb8238d0209a"), "event_id" : 2, "visit" : 1 } 

如果仅存在具有event_id 1的记录,则命令后的实际数据。

 { "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 2 } 

这 – 正确 – 将不会插入event_id 1或2的任何记录(如果它们尚不存在)

db.foo.update({event_id: { $in: [1,2]}}, {$inc: {visit:1}}, true, true)

这是因为查询的objNew部分(请参阅http://www.mongodb.org/display/DOCS/Updating#Updating-UpsertswithModifiers )没有字段event_id的值。 因此,您需要至少X + 1次访问数据库,其中X是event_ids的数量,以确保您插入记录(如果某个特定event_id不存在)(+1来自上面的查询,这增加了现有记录的访问计数器)。 以不同的方式说,MongoDB如何知道你想为event_id使用值2而不是1? 为什么不是6?

使用ruby进行Wrt批量插入,我认为可以通过以下链接建议 – 虽然我只使用了Java驱动程序: 使用Mongoid批量插入/更新?

你所追求的是查找和修改命令,其中up​​sert选项设置为true。 请参阅Mongo测试套件中的示例 (链接到查找和修改文档中的相同示例),以获得与您在问题中描述的内容非常相似的示例。

我找到了一种方法,使用eval运算符执行服务器端代码。 这是代码snippit:

 def batchpush(body, item_opts = {}) @batch << { :body => body, :duplicate_key => item_opts[:duplicate_key] || Mongo::Dequeue.generate_duplicate_key(body), :priority => item_opts[:priority] || @config[:default_priority] } end def batchprocess() js = %Q| function(batch) { var nowutc = new Date(); var ret = []; for(i in batch){ e = batch[i]; //ret.push(e); var query = { 'duplicate_key': e.duplicate_key, 'complete': false, 'locked_at': null }; var object = { '$set': { 'body': e.body, 'inserted_at': nowutc, 'complete': false, 'locked_till': null, 'completed_at': null, 'priority': e.priority, 'duplicate_key': e.duplicate_key, 'completecount': 0 }, '$inc': {'count': 1} }; db.#{collection.name}.update(query, object, true); } return ret; } | cmd = BSON::OrderedHash.new cmd['$eval'] = js cmd['args'] = [@batch] cmd['nolock'] = true result = collection.db.command(cmd) @batch.clear #pp result end 

使用batchpush()添加多个项目,然后调用batchpush() 。 数据作为数组发送,命令全部执行。 此代码在此文件中的MongoDequeue GEM中使用。

只发出一个请求,并且所有upsert都发生在服务器端。