我需要通过"默认值"来更新MongoDB中的所有文档。文件:如果"默认值的任何部分"在DB文档中不存在 - 添加此部分,否则不要修改此部分。
我试图通过存储的函数来实现这一点:加载doc,递归更新它,保存它。
insertDefValues.js:
db.system.js.save({_id: "DoInsertDefValues", value: function(data, defValues)
{
var modified = false;
for (var prop in defValues)
{
if (data[prop] === undefined)
{
data[prop] = defValues[prop];
modified = true;
}
else if (typeof defValues[prop] === "object")
modified |= DoInsertDefValues(data[prop], defValues[prop]);
}
return modified;
}});
db.system.js.save({_id: "InsertDefValues", value: function()
{
var defValues = {
//...
};
var docs = db.collection.find();
docs.forEach(function(data)
{
if (DoInsertDefValues(data, defValues))
db.collection.save(data);
});
}});
db.loadServerScripts();
InsertDefValues();
然后我通过mongo shell执行它:
mongo collection insertDefValues.js
问题是这种方法太慢了(测试数据的2K文档上30秒,生产数据库要大得多)。我使用没有批量更新的MongoDB 2.4.10,所以这不是一个选项。我将尝试生成一系列更新,例如:
E.g。对于"默认值":{"1": {"2": "blah"}}
更新
db.collection.update({"1": {$exists: false}}, {$set: {"1": {"2": "blah"}}})
db.collection.update({"1.2": {$exists: false}}, {$set: {"1.2": "blah"}})
还有其他选择吗?
"默认值" doc是7KB紧凑的JSON,没有字符串值。 收集文档的平均大小是10KB的紧凑型JSON。
我可以使用MongoDB-CSharp驱动程序,如果它能产生明显更快的解决方案(我对此表示怀疑)。
答案 0 :(得分:1)
我在你的代码中发现了一些内容,可能是错误。
InsertDefValues (data, defValues);
应为 DoInsertDefValues (data, defValues);
,对吧?
保存前不会返回并检查 DoInsertDefValues 中的已修改,这意味着您将保存每个文档,对吗?
脚本在mongo shell - 客户端执行,这可能会降低性能,因为从服务器接收数据并为每个保存操作处理连接套接字的内容。我从mongodb驱动程序中学习了java的这些动作,如果mongo shell与其他驱动程序原理相同,这将是性能低下的主要原因。如果尚未对分片进行分片,则调用db.eval
以使脚本在服务器端执行。祝你好运。
答案 1 :(得分:0)
通过生成递归更新解决问题(如问题中所述)。执行时间从30秒降至0.5秒。