Mongo批量在单个查询中查找和更新匹配的文档字段?

时间:2016-10-19 07:08:56

标签: mongodb mongodb-query

我有一个存储在mongo中的元图库。每当网站查询匹配一定数量的存储图像时,我希望文档shown计数器字段递增。使用findAndModify对于单个文档可以正常工作,但我看不到匹配多个文档并更新所有文档的好方法。

这是否可以使用最新版本的mongo?或者任何推荐的最佳实践来实现这一目标?

感谢 FLO

文档格式非常简单

{
"name"         : "img name",
"description"  : "some more info",
"size"         : "img size in bytes",
"shown"        : "count of times the image was selected by query",
"viewed"       : "count of times the image was clicked"
}

查询是一个简单的查找,然后使用游标循环结果并使用文档ID突破显示的计数..即

db.images.update(
   { _id: "xxxx" },
   { $inc: { shown: 1 } }
)

但是我不想获得100个文档,然后必须循环遍历每个文档以单独更新。希望在单个查询中执行查找和更新。

1 个答案:

答案 0 :(得分:1)

为了提高性能,请利用 Bulk() API有效地批量更新集合,因为您将批量发送操作到服务器(例如,批量大小为500)。这样可以提供更好的性能,因为您不会向服务器发送每个请求,而是每500个请求中只发送一次请求,从而使您的更新更加高效和快捷。

以下演示了此方法,第一个示例使用MongoDB版本中的 Bulk() API> = 2.6和< 3.2。它通过将1递增到显示的字段来更新给定数组中集合中的所有匹配文档。它假设图像阵列具有结构

var images = [
    { "_id": 1, "name": "img_1.png" },
    { "_id": 2, "name": "img_2.png" }
    { "_id": 3, "name": "img_3.png" },
    ...
    { "_id": n, "name": "img_n.png" }
]

MongoDB版本> = 2.6和< 3.2

var bulk = db.images.initializeUnorderedBulkOp(),
    counter = 0;

images.forEach(function (doc) {    
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$inc": { "shown": 1 }
    });

    counter++;
    if (counter % 500 === 0) {
        // Execute per 500 operations
        bulk.execute(); 
        // re-initialize every 500 update statements
        bulk = db.images.initializeUnorderedBulkOp();
    }
})
// Clean up remaining queue
if (counter % 500 !== 0) { bulk.execute(); }

下一个示例适用于自deprecated Bulk() API以来的新MongoDB版本3.2,并使用 {{3}提供了一套更新的api }

MongoDB 3.2及更高版本

var ops = [];
images.forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$inc": { "shown": 1 }
            }
        }
    });

    if (ops.length === 500 ) {
        db.images.bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  
    db.images.bulkWrite(ops);