使用up with update时,驱动程序会组合查询和$ 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上有一个索引。
答案 0 :(得分:3)
基本上不,查询中指定的值不会覆盖与该查询匹配的文档所在的位置。
"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" }
这清楚地表明语句的查询部分不用于写入实际更新。因此,这仅在插入时发生,并且仅在与语句的更新文档部分中存在的更新运算符一起使用时才会发生