Change an existing object in an array but still pr

2019-05-10 18:51发布

问题:

I have a document:

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

If I want to add new object to the profile_set only if the name of the object isn't already taken, regardless of the options, I can qualify my update with a query object that prevents the update if the name is already present in profile_set. In the shell:

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

So this will only perform the $push for a doc with a matching _id and where there isn't a profile_set element where name is 'nick'.

Question But if I later need to change Nick's name (and maybe his options too...), that is change an existing array object, not add a new one. Is there a way to do that in one atomic update operation that still honor the unique constraint of name?

回答1:

There are two conditions, I think:

var newName = "somename";
var oldName = "nick";
var newOption = 3;

// if not change the name
db.coll.update({
    _id : id,
    'profile_set.name' : oldName
}, {
    $set : {
        "profile_set.$.options" : newOption
    }
});

// if change the name
db.coll.update({
    _id : id,
    $and : [ {
        'profile_set.name' : {
            $ne : newName
        }
    }, {
        'profile_set.name' : oldName    
    } ]
}, {
    $set : {
        "profile_set.$.name" : newName,
        "profile_set.$.options" : newOption

    }
});