使用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批量插入/更新?
你所追求的是查找和修改命令,其中upsert选项设置为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都发生在服务器端。