在upsert更新时,mongodb $ addToSet设置为非数组字段 [英] mongodb $addToSet to a non-array field when update on upsert

查看:554
本文介绍了在upsert更新时,mongodb $ addToSet设置为非数组字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近的项目遇到了与此相同的问题:

My recent project encountered the same problem as this one: the question

db.test.update(
    {name:"abc123", "config.a":1  }, 
    {$addToSet:{ config:{a:1,b:2} } }, 
    true 
)

会产生这样的错误:

不能将$ addToSet应用于非数组字段

Cannot apply $addToSet to a non-array field

但更改为:

db.test.update(
    {name:"abc123", "config.a":{$in:[1]}  }, 
    {$addToSet:{ config:{a:1,b:2} } }, 
    true 
)

工作正常.

It works fine.

还引用了此链接:答案

任何人都可以解释发生了什么吗? "config.a":1 会将 config 变成对象吗? "config.a":{$ in:[1]} 在哪里?

Can Any one explain what's going on? "config.a":1 will turn config to be an object? Where "config.a":{$in:[1]} won't?

推荐答案

您要在此处执行的操作是仅在不存在该项的情况下将新项添加到数组中,并在不存在的项中创建一个新文档.选择$addToSet是因为您希望项目是唯一的,但实际上您真的希望它们仅通过"a"来唯一.

What you are trying to do here is add a new item to an array only where the item does not exist and also create a new document where it does not exist. You choose $addToSet because you want the items to be unique, but in fact you really want them to be unique by "a" only.

所以$addToset不会这样做,而您需要测试"存在的元素.但是这里真正的问题是不可能同时进行和向上插入".该逻辑无法正常工作,因为只要找不到数组元素,就会创建新文档,而不是像您想要的那样追加到数组元素.

So $addToset will not do that, and you rather need to "test" the element being present. But the real problem here is that it is not possible to both do that and "upsert" at the same time. The logic cannot work as a new document will be created whenever the array element was not found, rather than append to the array element like you want.

当前设计为$addToSet的当前操作错误不能用于创建"数组,而只能用于添加"成员到现有数组.但是如上所述,在实现逻辑上还有其他问题.

The current operation errors by design as $addToSet cannot be used to "create" an array, but only to "add" members to an existing array. But as stated already, you have other problems with achieving the logic.

这里您需要的是一系列更新操作,每个尝试"执行更新操作的预期动作.这只能通过多个语句来完成:

What you need here is a sequence of update operations that each "try" to perform their expected action. This can only be done with multiple statements:

// attempt "upsert" where document does not exist
// do not alter the document if this is an update
db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 2 }] }},
    { "upsert": true }
)

// $push the element where "a": 1 does not exist
db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 2 } }}
)

// $set the element where "a": 1 does exist
db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 2 } }
)

在第一次迭代中,第一条语句将向上插入"文档并创建包含项的数组.第二条语句将与文档不匹配,因为"a"元素具有指定的值.第三条语句将与文档匹配,但由于值未更改,因此不会在写操作中对其进行更改.

On a first iteration the first statement will "upsert" the document and create the array with items. The second statement will not match the document because the "a" element has the value that was specified. The third statement will match the document but it will not alter it in a write operation because the values have not changed.

如果您现在将输入更改为"b": 3,则会得到不同的响应,但希望得到的结果是:

If you now change the input to "b": 3 you get different responses but the desired result:

db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 3 }] }},
    { "upsert": true }
)

db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 3 } }}
)

db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 3 } }
)

因此,现在第一条语句将文档与"name": "abc"匹配,但由于仅在插入"上执行了有效操作,因此不执行任何操作.第二个语句不匹配,因为"a"与条件匹配.第三句话匹配值"a",并将匹配元素中的"b"更改为所需值.

So now the first statement matches a document with "name": "abc" but does not do anything since the only valid operations are on "insert". The second statement does not match because "a" matches the condition. The third statment matches the value of "a" and changes "b" in the matched element to the desired value.

随后将"a"更改为数组中不存在的另一个值,则1和3都无法执行任何操作,但第二条语句将另一个成员添加到数组中,并通过其"a"键保持内容唯一.

Subsequently changing "a" to another value that does not exist in the array allows both 1 and 3 to do nothing but the second statement adds another member to the array keeping the content unique by their "a" keys.

如果提交的现有数据没有任何变化的声明,当然也会得到一个响应,表明所有帐户均未更改.

Also submitting a statement with no changes from existing data will of course result in a response that says nothing is changed on all accounts.

这就是您进行操作的方式.您可以通过有序"的批量操作来执行此操作,这样,只有一个请求和响应来自具有对修改或创建的有效响应的服务器.

That's how you do your operations. You can do this with "ordered" Bulk operations so that there is only a single request and response from the server with the valid response to modified or created.

这篇关于在upsert更新时,mongodb $ addToSet设置为非数组字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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