【问题标题】:MongoDB: bulk update to insert missing partsMongoDB:批量更新以插入缺失的部分
【发布时间】:2014-08-22 08:45:58
【问题描述】:

我需要通过“默认值”文档更新 MongoDB 中的所有文档:如果 DB 文档中不存在“默认值”的任何部分 - 添加此部分,否则不要修改此部分。

我尝试通过存储函数来实现:加载文档,递归更新,保存。

插入DefValues.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,所以这不是一个选项。我将尝试生成一系列更新,例如:

例如对于“默认值”:{"1": {"2": "blah"}}

更新:

db.collection.update({"1": {$exists: false}}, {$set: {"1": {"2": "blah"}}})
db.collection.update({"1.2": {$exists: false}}, {$set: {"1.2": "blah"}})

还有其他选择吗?

“默认值”文档是 7KB 紧凑型 JSON,没有字符串值。 集合文档的平均大小为 10KB 的紧凑型 JSON。

如果 MongoDB-CSharp 驱动程序可以产生明显更快的解决方案,我可以使用它(我对此表示怀疑)。

【问题讨论】:

  • 嗯,如果文档中不存在某个值,则计算结果为null。因此,如果字段为null,您可以使用您的模型/DAO 返回默认值。将来更容易更改,存储到磁盘的不必要数据更少。
  • @MarkusWMahlberg:我正在通过生成的序列化程序存储 C# 结构。我想明确存储默认值(包括 C# 内联初始化程序和在构造函数中分配的值),除了 C#“本机”默认值(default(T)),以避免在初始化逻辑更改时意外隐式更改已保存的数据。此外,我不想将默认值与数据结构定义分开存储。

标签: mongodb


【解决方案1】:

我在你的代码中发现了一些东西,可能是错误。

InsertDefValues(data, defValues); 应该是 DoInsertDefValues(data, defValues);,对吧?

DoInsertDefValues中的modified不会在保存前返回和检查,也就是说你会保存每一个文档,对吧?

脚本在 mongo shell - 客户端执行,这可能会降低性能,因为从服务器接收数据并为每次保存操作处理连接套接字。我是从 mongodb driver for java 学来的这些动作,如果 mongo shell 的原理和其他驱动一样,这将是性能低下的主要原因。如果集合没有被分片,调用db.eval 让脚本在服务器端执行。祝你好运。

【讨论】:

    【解决方案2】:

    通过生成递归更新解决了问题(如问题中所述)。执行时间从 30 秒降至 0.5 秒。

    【讨论】:

    • 我可以知道你的generating recursive updates 是什么来取得这么大的进步吗?
    • @Wizard:我在问题中简要描述的“更新系列”。也许最大的区别是您在回答中提到的内容:大多数执行发生在服务器端,减少了 shell-服务器通信。我会尝试 db.eval 来比较结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 1970-01-01
    • 2014-10-06
    • 2012-02-16
    • 1970-01-01
    相关资源
    最近更新 更多