您可以在Mongo中为$ addToSet指定密钥吗?


70

我有一个文件:

{ 'profile_set' :
  [
    { 'name' : 'nick', 'options' : 0 },
    { 'name' : 'joe',  'options' : 2 },
    { 'name' : 'burt', 'options' : 1 }
  ] 
}

并想将新文档添加到profile_set集中(如果该名称不存在)(无论该选项如何)。

因此,在此示例中,如果我尝试添加:

{'name' : 'matt', 'options' : 0}

它应该添加它,但是添加

{'name' : 'nick', 'options' : 2}

不应执行任何操作,因为nick即使名称option不同,文档名称也已存在。

Mongo似乎与整个元素匹配,我最终检查它是否相同,最后我得到

profile_set containing [{'name' : 'nick', 'options' : 0}, {'name' : 'nick', 'options' : 2}]

有没有办法用$ addToSet做到这一点,或者我必须推送另一个命令?


由于您不能保证$ addToSet将首先运行,因此您将需要两个命令来执行此操作
Sammaye 2013年

Answers:


97

您可以update使用阻止更新的查询对象来限定您的身份(如果name已存在)profile_set。在外壳中:

db.coll.update(
    {_id: id, 'profile_set.name': {$ne: 'nick'}}, 
    {$push: {profile_set: {'name': 'nick', 'options': 2}}})

因此,这将只执行$push与匹配一个文档_id和那里没有一个profile_set地方元素name'nick'


1
如果以后需要更改mick的名称,那就是更改现有的数组对象,而不要添加新的对象。有没有一种方法可以在一次原子更新操作中仍然尊重名称的唯一约束呢?
安德斯·奥斯曼(AndersÖstman)2014年

关于更改profile_set中现有对象的后续问题:stackoverflow.com/questions/26590219/…
安德斯·奥斯曼(AndersÖstman)2014年

3
我到处解决猫鼬或猫鼬问题的任何地方,@ JohnnyHK总是救了我。
Jinyoung Kim

5
@JohnnyHK如果需要覆盖该值,该怎么办?
Alex Zhukovskiy

2
敬请任何人回答上面的@Alex问题。如果元素已经存在,则需要什么来更新该元素?
raj

2

从MongoDB 4.2开始,有一种方法可以在update中使用聚合表达式来实现

对于您的示例案例,您可以这样做:

newSubDocs = [ {'name' : 'matt', 'options' : 0}, {'name' : 'nick', 'options' : 2} ];
db.coll.update( { _id:1 },
[ 
   {$set:  { profile_set:  {$concatArrays: [ 
      "$profile_set",  
      {$filter: {
             input:newSubDocs, 
             cond: {$not: {$in: [ "$$this.name", "$profile_set.name" ]}} 
      }}
   ]}}}
])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.