10

I have an object that looks like this.

{
  _id: '577fe7a842c9b447',
  name: 'Jacob\'s Bronze Badges',
  competitors: [
    {
      _id: '577fe7a842c9bd6d',
      name: 'Peter\'s Silver Badges',
      sites: [
        {
          _id: '577fe7a842c9bd6d',
          name: 'Facebook',
          url: 'fb.com/peter'
        },
        {
          _id: '577fe7a842c9bd6d'
          name: 'Google',
          url: 'google.com/peter'
        }
      ]
    },
    {
      _id: '599fe7a842c9bd6d',
      name: 'Paul\'s Gold Badges',
      sites: [
        {
          '_id': '577fe7a842c9bd6d',
          name: 'Facebook',
          url: 'fb.com/paul'
        },
        {
          _id: '577fe7a842c9bd6d',
          name: 'Google',
          url: 'google.com/paul'
        }
      ]
    }
  ]
}

My goal is to reference the competitors array and update items inside with all of the values from req.body. I based this code off of this answer, as well as this other one.

Location.update(
  { 'competitors._id': req.params.competitorId, },
  { $set: { 'competitors.$': req.body, }, },
  (err, result) => {
    if (err) {
      res.status(500)
      .json({ error: 'Unable to update competitor.', });
    } else {
      res.status(200)
      .json(result);
    }
  }
);

I send my HTTP PUT to localhost:3000/competitors/577fe7a842c9bd6d to update Peter's Silver Badges. The request body is:

{
  "name": "McDonald's"
}

The problem is that when I use $set to set the competitor with _id: req.params.competitorId, I don't know what is in req.body. I want to use the entire req.body to update the object in the array, but when I do, that object is overwritten, so instead of getting a new name, Peter's Silver Badges becomes:

{
  name: 'McDonald\'s',
  sites: []
}

How can I update an object within an array when I know the object's _id with all of the fields from req.body without removing fields that I want to keep?

I believe that the sites array is empty because the object was reinitialized. In my schema I have sites: [sitesSchema] to initialize it. So I am assuming that the whole competitors[_id] object is getting overwritten with the new name and then the sites: [sitesSchema] from myschema.

2 Answers 2

14

You would need to use the $ positional operator in your $set. In order to assign those properties dynamically, based on what is in your req.body, you would need to build up your $set programmatically.

If you want to update the name you would do the following:

Location.update(
  { 'competitors._id': req.params.competitorId },
  { $set:  { 'competitors.$.name': req.body.name }},
  (err, result) => {
    if (err) {
      res.status(500)
      .json({ error: 'Unable to update competitor.', });
    } else {
      res.status(200)
      .json(result);
    }
 }
);

One way you might programatically build up the $set using req.body is by doing the following:

let updateObj = {$set: {}};
for(var param in req.body) {
  updateObj.$set['competitors.$.'+param] = req.body[param];
 }

See this answer for more details.

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

1 Comment

yes it is working but in my code i have to send two request for a query to exexute it. ```
3

To update embedded document with $ operator, in most of the cases, you have to use dot notation on the $ operator.

Location.update(
  { _id: '577fe7a842c9b447', 'competitors._id': req.params.competitorId, },
  { $set: { 'competitors.$.name': req.body.name, }, },
  (err, result) => {
    if (err) {
      res.status(500)
      .json({ error: 'Unable to update competitor.', });
    } else {
      res.status(200)
      .json(result);
    }
  }
);

Comments

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.