MongoDB:upsert子文档 [英] MongoDB: upsert sub-document

查看:252
本文介绍了MongoDB:upsert子文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的文档看起来像这样,在bars.name上具有唯一索引:

I have documents that looks something like that, with a unique index on bars.name:

{ name: 'foo', bars: [ { name: 'qux', somefield: 1 } ] }

.我想更新{ name: 'foo', 'bars.name': 'qux' }$set: { 'bars.$.somefield': 2 }的子文档,或者在{ name: 'foo' }下用{ name: 'qux', somefield: 2 }创建一个新的子文档.

. I want to either update the sub-document where { name: 'foo', 'bars.name': 'qux' } and $set: { 'bars.$.somefield': 2 }, or create a new sub-document with { name: 'qux', somefield: 2 } under { name: 'foo' }.

是否可以使用带有upsert的单个查询来执行此操作,还是我必须发布两个单独的查询?

Is it possible to do this using a single query with upsert, or will I have to issue two separate ones?

相关:在嵌入式文档中"upsert" (建议更改架构以子文档标识符作为关键字,但这是两年前的事,我想知道现在是否有更好的解决方案.)

Related: 'upsert' in an embedded document (suggests to change the schema to have the sub-document identifier as the key, but this is from two years ago and I'm wondering if there are better solutions now.)

推荐答案

没有真正更好的解决方案,所以也许要附上解释.

No there isn't really a better solution to this, so perhaps with an explanation.

假设您有一个文档,该文档的结构如下所示:

Suppose you have a document in place that has the structure as you show:

{ 
  "name": "foo", 
  "bars": [{ 
       "name": "qux", 
       "somefield": 1 
  }] 
}

如果您进行这样的更新

db.foo.update(
    { "name": "foo", "bars.name": "qux" },
    { "$set": { "bars.$.somefield": 2 } },
    { "upsert": true }
)

那么很好,因为找到了匹配的文档.但是,如果您更改"bars.name"的值:

Then all is fine because matching document was found. But if you change the value of "bars.name":

db.foo.update(
    { "name": "foo", "bars.name": "xyz" },
    { "$set": { "bars.$.somefield": 2 } },
    { "upsert": true }
)

然后您将失败.唯一真正改变的地方是在MongoDB 2.6及更高版本中,错误更为简洁:

Then you will get a failure. The only thing that has really changed here is that in MongoDB 2.6 and above the error is a little more succinct:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 16836,
        "errmsg" : "The positional operator did not find the match needed from the query. Unexpanded update: bars.$.somefield"
    }
})

从某些方面讲,这是更好的选择,但是您实际上绝对不想增补".您要做的是将元素添加到当前不存在名称"的数组中.

That is better in some ways, but you really do not want to "upsert" anyway. What you want to do is add the element to the array where the "name" does not currently exist.

因此,您真正想要的是更新尝试中的结果",而没有"upsert"标志,以查看是否有文档受到影响:

So what you really want is the "result" from the update attempt without the "upsert" flag to see if any documents were affected:

db.foo.update(
    { "name": "foo", "bars.name": "xyz" },
    { "$set": { "bars.$.somefield": 2 } }
)

回应:

WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })

因此,当修改后的文档为0时,您就知道要发布以下更新:

So when the modified documents are 0 then you know you want to issue the following update:

db.foo.update(
    { "name": "foo" },
    { "$push": { "bars": {
        "name": "xyz",
        "somefield": 2
    }}
)

确实没有其他方法可以完全满足您的需求.由于对数组的添加并不是严格意义上的设置"操作,因此不能将$addToSet批量更新" 功能,以便您可以级联"更新请求.

There really is no other way to do exactly what you want. As the additions to the array are not strictly a "set" type of operation, you cannot use $addToSet combined with the "bulk update" functionality there, so that you can "cascade" your update requests.

在这种情况下,您似乎需要检查结果,或者接受阅读整个文档并检查是否在代码中更新或插入新的数组元素.

In this case it seems like you need to check the result, or otherwise accept reading the whole document and checking whether to update or insert a new array element in code.

这篇关于MongoDB:upsert子文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆