1

I have a nested objects like this:

{
   fits: {
      honda: {
         shadows: {
            2000: true,
            2001: true,
            2003: true
         }
      }
   }
}

I want to add new models so it would look something like this:

{
   fits: {
      honda: {
         shadows: {
            2000: true,
            2001: true,
            2003: true
         },
         aaaa: {},
         bbbb: {}
         ...
      }
   }
}

and later years:

{
   fits: {
      honda: {
         shadows: {
            2000: true,
            2001: true,
            2003: true
         },
         aaaa: {
            1990: true,
            ...
         },
         bbbb: {}
         ...
      }
   }
}

I am able to add new makes:

{
   fits: {
      honda: {
         shadows: {
            2000: true,
            2001: true,
            2003: true
         },
      },
      kawasaki: {},
      ...
   }
}

But when I want to add a new model for example to honda it will erase the previous one and than put in new one:

{
   fits: {
      honda: {
         aaaa: {},
      }
   }
}

For adding new makes I am using this code and it works just fine:

data.fits[newMake] = {}
this.state.client.auth.loginWithCredential(new AnonymousCredential()).then((user) => {
   this.state.db.collection('products').findOneAndUpdate(
      {_id: data._id}, {$set:{fits: data.fits}}, {returnNewDocument: true}
   ).then((result)=>{
      this.setState({
         rowData: result,
      })
   }).catch((e)=>console.log(e))
})

Here is the one i use for inputing new models, but it keeps erasing the other model so I'm always left with just one model:

var query = {}
query[make] = {}
query[make][addedModel] = {}
this.state.client.auth.loginWithCredential(new AnonymousCredential()).then((user) => {
   this.state.db.collection('products').findOneAndUpdate(
      {_id: _id},{$set:{fits: query}},{returnNewDocument: true}
   ).then((result)=>{
      console.log(result)
      this.props._handleAddModel(result)
   }).catch((e)=>console.log(e))
}); 

I think that $set data just sets the new data without preserving the old, but than why it works on makes and not on models? Am I understanding the $set wrong?

I looked for other atomic operators but couldn't find anything that would just add the new field without erasing other fields.

1
  • I think you have confused 'makes' and 'models' code in the function. The first code sample should erase all previous 'makes' and add honda, while the second one is working as expected. Commented May 15, 2020 at 15:06

2 Answers 2

3

You are overwriting the entire fits property in this line:

{_id: data._id}, {$set:{fits: data.fits}}, {returnNewDocument: true}

Make the following update to it:

const updateData = {
    [`fits.${newMake}`]: data.fits,
};
{_id: data._id}, {$set: updateData}, {returnNewDocument: true}

This way you are making an update to just the newMake sub-property

Also make sure that newMake is not falsy (empty string, undefined, null, ...)

Sign up to request clarification or add additional context in comments.

1 Comment

Sorry for a long response. This definitely helped but instead of [`fits.${newMake}`]: data.fits I did [`fits.${make}.${addedModel}`]: {} since I need the model to be an object too. But the functionality stays the same. Thanks a bunch :)
1

I think that $set data just sets the new data without preserving the old

Yes, you're correct. From MongoDB docs:

The $set operator replaces the value of a field with the specified value.

But also,

If the field does not exist, $set will add a new field with the specified value, provided that the new field does not violate a type constraint. If you specify a dotted path for a non-existent field, $set will create the embedded documents as needed to fulfill the dotted path to the field.

When you say:

$set:{fits: data.fits}

This replaces the value of fits with data.fits (i.e. { honda: {} } ), since the field exists.

And when you say:

$set:{fits: query}

since the path fits[make][addedModel] does not exist, mongoDB creates it, and hence you do not lose previous data. [ Going as per docs, this should not work as well, since you are not specifying a dotted path, but probably is working due to a bug ]

1 Comment

Yeah that is what confused me a bit, cause when I looked at adding the new make it should replace the old one with the new, but for some reason it adds a new one without replacing which is exactly what I want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.