【问题标题】:Does mongodb upsert use the query fieldmongodb upsert 是否使用查询字段
【发布时间】:2014-10-16 23:26:10
【问题描述】:

当使用带有 upsert 的更新时,驱动程序是否将查询和 $set 对象结合起来。

这是一些示例代码

db.collection('objects').update({_key: 'test1'}, {$set: {a:1}}, {upsert: true, w: 1}, callback);

当我这样做时,如果文件 test1 不存在,mongo 似乎会插入以下文件。

{
 _id: ,
 _key: 'test1',
  a: 1
}

因此它从查询中获取键并将其用作字段以及a:1

这和以下有什么不同:

var data = {
   _key : 'test1',
   a: 1
};

db.collection('objects').update({_key: 'test1'}, {$set: data}, {upsert: true, w: 1}, callback);

第二个会因为覆盖_key而变慢吗? _key 上有一个索引。

【问题讨论】:

    标签: javascript node.js mongodb mongodb-query


    【解决方案1】:

    基本上不会,查询中指定的值不会覆盖与该查询匹配的文档所在的位置。

    "upsert" 的基本工作原理是查询部分中设置的条件首先查找与这些条件匹配的文档。如果文档存在,则语句的“更新文档”部分中提供的任何参数都用于写入匹配的文档。在这种情况下,只有使用 $set 运算符指定的字段,因此这些是唯一被触及的字段,而不是发送会覆盖现有文档的整个对象。

    如果文档不匹配,则首先将查询条件中指定的任何值写入新文档。这是有道理的,因为您要的是满足这些条件但不存在的文档。

    然后(但实际上是一次)语句的“更新文档”部分中的任何值也将应用于新文档。您还可以使用 $setOnInsert 运算符指定要在“插入”上创建的字段,这些字段不存在于查询部分中,因此这些值仅在创建时使用。

    事实上,证明这一点的一个好方法是执行两个“upsert”操作,如下所示:

    db.test.update({ "a": "test" },{ "$set": { "b": "data" } },{ "upsert": true});
    db.test.update({ "a": "test" },{ "b": "data" },{ "upsert": true});
    

    如果没有任何更新操作符,您只是在第二次迭代中发送整个文档。这意味着当第一次发生“插入”时,您将拥有这样的文档:

    { "a": "test", "b": "data" }
    

    当然,当您执行与字段“a”等于“test”的文档匹配的第二次更新时,结果文档是这样的:

    { "b": "data" }
    

    这清楚地表明语句的查询部分不用于写入实际更新。因此,这只发生在插入时,并且仅在与语句的更新文档部分中存在的更新运算符一起使用时发生

    【讨论】:

    • 如果我们使用与原始不同的 _key 值进行更新,var data = { _key : 'test2', a: 1 };
    • @chianh 然后在更新部分指定要“更改”的值:{ "_key": "test1},{ "$set": { "_key": "test2", "a": 1 } }。查询文档用于“匹配”,仅适用于插入。您在更新文档中输入的任何内容都会被应用。您不能“覆盖”_id BTW。
    • 谢谢@Neil。我还不够清楚:在 _key=test1 不存在的情况下,这会插入 _key=test2 吗?
    • @chianh upsert 意味着如果没有找到匹配的文档,则插入一个新文档。由于在更新文档中为 _key 指定了一个值作为“test2”,如果没有找到带有“test1”的文档,则会创建一个带有“test2”的新文档,因为您要求它覆盖 _key 的值。这是所问问题的相反情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-20
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    相关资源
    最近更新 更多