dhj
dhj

Reputation: 4805

mongoose findOneAndUpdate appends objects only

I have an object like follows;

var exObj = { 'title' : 'name1'};

some of them have a data property of objects (not an array as I want to reference by name) and look like

  exObj = {
    title : 'name2',
    data : {
      prop1 : 'prop1',
      prop2 : 'prop2'
    }
  }

Now I want to add another property to data, sometimes the data property will exist, and sometimes not, but I want to append a property (addedProp) and save it so I will end up with this;

 exObj = {
    title : 'name2',
    data : {
      prop1 : 'prop1',
      prop2 : 'prop2',
      addedProp : 'value'
    }
  }

When using findOneAndUpdate I can only seem to pass in a whole object which is then appended; something like this is what I currently do.

var data = {};
data.addedProp = value;

Collection.findOneAndUpdate({
  title: 'name2'
}, {
  data
}, {
  upsert: true
})
.exec(function(err) {
  if (err) {
    console.log(err);
  } else {
    console.log('Updated');
  }
});

But obviously this overides the data object that exists; what is the correct way to do a findOneAndUpdate and make more meaningful changes to the object? I tried casting to toObject() but then I don't have a proper mongoose object to do a .save() on.

To add further clarification; which this worked for simple properties (and worked well) which I know are set; there are some values I wish to add which I need to check if they have a value for the property before adding the property.

So something like this;

    Collection.findOneAndUpdate({
      field: val
      }, {
      if (tObj.title) {
        title = tObj.title;
      }

      if (tObj.date) {
        release_date = tObj.date;
      }

      if (tObj.name) {
        name = tObj.name;
      }
    }, { upsert: true
    })
    .exec(function(err) {
    if (err) {
     //handler
    } else {
    //handler
    }
  });

Upvotes: 3

Views: 2723

Answers (2)

JohnnyHK
JohnnyHK

Reputation: 312035

You need to use dot notation to target specific fields within an embedded object, building up your update object based on the supplied fields:

var update = {};
if (tObj.title) {
    update.title = tObj.title;
}
if (tObj.data) {
    if (tObj.data.prop1) {
        update['data.prop1'] = tObj.data.prop1;
    }
    if (tObj.data.prop2) {
        update['data.prop2'] = tObj.data.prop2;
    }
    if (tObj.data.addedProp) {
        update['data.addedProp'] = tObj.data.addedProp;
    }
}

Collection.findOneAndUpdate({
  title: 'name2'
}, {
  $set: update
}, {
  upsert: true
})
.exec(function(err) {

Upvotes: 0

Puneet Singh
Puneet Singh

Reputation: 3543

Your question first seem daunting, but solution is quite simple, you don't need to use $ or upsert, because you are not using any array , so don't need of positional operator or upsert. You can use below code.

Collection.findOneAndUpdate({
  title: 'name2'
},{
    $set:{"data.prop3":"new prop3"}
})
.exec(function(err) {
  if (err) {
    console.log(err);
  } else {
    console.log('Updated');
  }
});

It will add prop3 if not exists, or if it exists it will update it. I have checked the code on my local db with update and findOneAndUpdate

Upvotes: 3

Related Questions