Mongodb - change object value within object array

Asked

Viewed 193 times

0

I have a Collection in mongodb called users containing the field (which is an array of objects) adress. I have the following piece of code to replace and change in the database:

async updateAdress(input) {
  const { idUser, idAdress, adressInfo } = input;
  let user = await User.findById(idUser);
  let counter = 0;

  console.log(adressInfo);
  let old = user.adressInfo;
  user.adressInfo.forEach(adress => {

    if (adress.id == idAdress) {
      old[counter] = adressInfo;

    }
    counter++;
  });
  console.log(old);
  return User.findByIdAndUpdate(idUser, { $set: { adressInfo: old } }, { new: true }).catch(
    err => console.error(err)
  );
}     

In the console.log values are right, but when entering into the database, the edited object gets all fields null and exchange the id. Does anyone know why?

  • 1

    From what I understand, you want to update a record that is contained within an array, right? Update a specific element that is a address. If it is, why not simplify using the operator $ mongodb?

  • I want to update an object that is inside an array, you can tell me the documentation or how to search about that operator $?

1 answer

1

Assuming that your users have a field of address as an array, let’s demonstrate the example case:

users: {
   name: '...',
   age: 20,
   // ...
   address: [
      {
        _id: '123',
        street: '...'
        // ...
      },
      {
        _id: '456',
        street: '...'
        // ...
      }
   ]
}

For updateAdress, we understand that you want to update an object of address specific. In this case its function could be a little more simplified, without the need to loop forEach and have to use if (adress.id == idAdress) {...}. Mongodb offers a feature that allows you to update an Object within an array. We use The positional $ Operator. It has a very simple syntax to indicate which object should be updated. In the example of the documentation, we have an example:

We have the document:

{
  _id: 4,
  grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 90, mean: 85, std: 8 }
  ]
}

And we want to update the object that has the grade equal to 90 and adjust the std for 7. We make use of the $:

db.collection.updateOne(
   { _id: 4, "grades.grade": 90 },  // filtramos o objeto incluso no array aqui
   { $set: { "grades.$.std" : 7 } } // usamos o "$" aqui
)

Result after update:

{
   "_id" : 4,
   "grades" : [
      { "grade" : 80, "mean" : 75, "std" : 8 },
      { "grade" : 85, "mean" : 90, "std" : 6 },
      { "grade" : 90, "mean" : 85, "std" : 7 }
   ]
}

Now let’s adapt to your code. Let’s use the method findOneAndUpdate of Mongoose. The ultimate logic would be something like this:

async updateAdress(input) {
  const { idUser, idAdress, adressInfo } = input;
  let user = await User.findById(idUser);
  let counter = 0;
  //                                              ↓↓↓ filtramos o objeto no array aqui
  return User.findOneAndUpdate({_id: idUser, 'address._id': idAdress  }, 
  //                     ↓↓↓ atualiza o primeiro documento que fez o "match" da query
  //                         e associa um novo valor a ele ("addressInfo")
    { $set: { 'adressInfo.$': addressInfo } }, { new: true }
  ).catch(
    err => console.error(err)
  );
}     

The positional operator $ identifies an element in an array to update without explicitly specifying the position of the element in the array.

Details:

  • the positional operator $ acts as a marker for the first element that corresponds to the query document, and
  • the array field should appear as part of the query document.

Obs:

Note that I used the _id, Because that’s usually the name of the id’s that Mongoose creates. I don’t know how you structured the code, but I believe if you make the adaptations, this answer may be useful.

In the.log console the values are right, but when entering in the database, the edited object gets all the fields null and exchange the id

it is difficult to understand without analyzing the logs, but this problem may be because the id specified user. Mongoose does not change the values of id, then if a new id was created, it is because a new element was created, this because of the { new: true }. Test your code again, substitute findByIdAndUpdate for findOneAndUpdate, etc....

Browser other questions tagged

You are not signed in. Login or sign up in order to post.