findOneAndUpdate overwriting attributes in 2+ level deep object passed as doc

。_饼干妹妹 提交于 2021-02-07 08:32:52

问题


Let's say I have this schema:

var UserSchema = new Schema({
    name : {
        firstName : String,
        lastName : String
    }
});

And I create this user:

User.create({
    name : {
        firstName : Bob,
        lastName : Marley
    }
}, function (err, user) {
    if(err) {
        return console.error(err);
    } else {
        return console.log(user);
    }
});

I noticed that if I do this:

User.findOneAndUpdate({_id: userId}, { name: { firstName : "Damian" } }, function (err, user) {
    if(err) {
        return console.error(err);
    } else {
        return console.log(user);
    }
});

My user now is:

user = {
    name : {
        firstName : "Damian"
    }
}

However, if I do this:

User.findOneAndUpdate({_id: userId}, { "name.firstName" : "Damian" }, function (err, user) {
    if(err) {
        return console.error(err);
    } else {
        return console.log(user);
    }
});

My user is:

user = {
    name : {
        firstName : "Damian",
        lastName : "Marley"
    }
}

Is there a way to pass an Object with not all of its attributes filled out to findOneAndUpdate, and keep the attributes that were there before, without getting rid of them? (same functionality as $set in Mongo). This is really annoying...


回答1:


Flatten your incomplete nested object with flat, like this:

var flatten = require('flat')

flatten({
    name : {
        firstName : "Damian"
    }
})

// { 
//   'name.firstName': 'Damian'
// } 

And now you can call findOneAndUpdate exactly as you did in your second example.




回答2:


If you pass actual full nested object to findOneAndUpdate() (or any other mongoose update method):

Model.findOneAndUpdate({ ... }, {
  name: {
    firstName : "Damian"
  }
})

You will overwrite the whole (nested) object, therefore removing all of its other properties from the document (in this case: lastName).

To update only specific properties of the nested object, not the whole object, you need to use full path to the nested properties.

{ "name.firstName" : "Damian" }

(this will leave lastName in the nested name object untouched)

But it can be annoying to take care of that manually, whenever you update nested object's properties.

Luckily, it's not a problem at all to flatten the update object you pass to findOneAndUpdate() - so it never ends up being more than one level deep.

There are many ways to do this, debated upon in this question: Fastest way to flatten / un-flatten nested JSON objects .

The quickest solution seems to be to use ready-made flat Node.js library.

var flatten = require('flat')

User.findOneAndUpdate(
  { _id: userId },
  // same as passing '{ "name.firstName": "Damian" }':
  flatten({
    name: {
      firstName : "Damian"
    }
  }), function (err, user) {
  if(err) {
    return console.error(err);
  } else {
    return console.log(user);
  }
});


来源:https://stackoverflow.com/questions/30278445/findoneandupdate-overwriting-attributes-in-2-level-deep-object-passed-as-doc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!