MongoDB:更新插入子文档 [英] MongoDB: upsert sub-document

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

问题描述

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

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

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

.我想更新子文档 where { 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:更新插入子文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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