我有一个存储在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个文档,然后必须循环遍历每个文档以单独更新。希望在单个查询中执行查找和更新。
答案 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);