[node.js] Mongoose, update values in array of objects

Is there a way to update values in an object?

{
  _id: 1,
  name: 'John Smith',
  items: [{
     id: 1,
     name: 'item 1',
     value: 'one'
  },{
     id: 2,
     name: 'item 2',
     value: 'two'
  }]
}

Lets say I want to update the name and value items for item where id = 2;

I have tried the following w/ mongoose:

var update = {name: 'updated item2', value: 'two updated'};
Person.update({'items.id': 2}, {'$set':  {'items.$': update}}, function(err) { ...

Problem with this approach is that it updates/sets the entire object, therefore in this case I lose the id field.

Is there a better way in mongoose to set certain values in an array but leave other values alone?

I have also queried for just the Person:

Person.find({...}, function(err, person) {
  person.items ..... // I might be able to search through all the items here and find item with id 2 then update the values I want and call person.save().
});

This question is related to node.js mongodb mongoose

The answer is


In mongoose we can update, like simple array

user.updateInfoByIndex(0,"test")

User.methods.updateInfoByIndex = function(index, info) ={
    this.arrayField[index]=info
    this.save()
}

Having tried other solutions which worked fine, but the pitfall of their answers is that only fields already existing would update adding upsert to it would do nothing, so I came up with this.

 Person.update({'items.id': 2}, {$set: {
    'items': { "item1",  "item2",  "item3",  "item4" } }, {upsert: 
true })

There is a mongoose way for doing it.

const itemId = 2;
const query = {
  item._id: itemId 
};
Person.findOne(query).then(doc => {
  item = doc.items.id(itemId );
  item["name"] = "new name";
  item["value"] = "new value";
  doc.save();

  //sent respnse to client
}).catch(err => {
  console.log('Oh! Dark')
});

model.update({"_id": 1, "items.id": "2"}, 
{$set: {"items.$.name": "yourValue","items.$.value": "yourvalue"}})

Mongodb document


In Mongoose, we can update array value using $set inside dot(.) notation to specific value in following way

db.collection.update({"_id": args._id, "viewData._id": widgetId}, {$set: {"viewData.$.widgetData": widgetDoc.widgetData}})

There is one thing to remember, when you are searching the object in array on the basis of more than one condition then use $elemMatch

Person.update(
   {
     _id: 5,
     grades: { $elemMatch: { grade: { $lte: 90 }, mean: { $gt: 80 } } }
   },
   { $set: { "grades.$.std" : 6 } }
)

here is the docs


update(
    {_id: 1, 'items.id': 2},
    {'$set': {'items.$[]': update}},
    {new: true})

Here is the doc about $[]: https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up.S[]


I had similar issues. Here is the cleanest way to do it.

    const personQuery = {
       _id: 1  
    }

    const itemID = 2;

    Person.findOne(personQuery).then(item => {
       const audioIndex = item.items.map(item => item.id).indexOf(itemID);
       item.items[audioIndex].name = 'Name value';
       item.save();
    });

For each document, the update operator $set can set multiple values, so rather than replacing the entire object in the items array, you can set the name and value fields of the object individually.

{'$set':  {'items.$.name': update.name , 'items.$.value': update.value}}

Below is an example of how to update the value in the array of objects more dynamically.

Person.findOneAndUpdate({_id: id}, 
{ 
  "$set": {[`items.$[outer].${propertyName}`]: value} 
},
{ 
  "arrayFilters": [{ "outer.id": itemId }]
},
function(err, response) {
  ...
})

Note that by doing it that way, you would be able to update even deeper levels of the nested array by adding additional arrayFilters and positional operator like so:

"$set": {[`items.$[outer].innerItems.$[inner].${propertyName}`]: value} 

"arrayFilters":[{ "outer.id": itemId },{ "inner.id": innerItemId }]

More usage can be found in the official docs.


Examples related to node.js

Hide Signs that Meteor.js was Used Querying date field in MongoDB with Mongoose SyntaxError: Cannot use import statement outside a module Server Discovery And Monitoring engine is deprecated How to fix ReferenceError: primordials is not defined in node UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac internal/modules/cjs/loader.js:582 throw err DeprecationWarning: Buffer() is deprecated due to security and usability issues when I move my script to another server Please run `npm cache clean`

Examples related to mongodb

Server Discovery And Monitoring engine is deprecated Avoid "current URL string parser is deprecated" warning by setting useNewUrlParser to true MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017] Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified Failed to start mongod.service: Unit mongod.service not found db.collection is not a function when using MongoClient v3.0 MongoError: connect ECONNREFUSED 127.0.0.1:27017 MongoDB: How To Delete All Records Of A Collection in MongoDB Shell? How to resolve Nodejs: Error: ENOENT: no such file or directory How to create a DB for MongoDB container on start up?

Examples related to mongoose

Querying date field in MongoDB with Mongoose Server Discovery And Monitoring engine is deprecated Avoid "current URL string parser is deprecated" warning by setting useNewUrlParser to true Mongodb: failed to connect to server on first connect Push items into mongo array via mongoose Mongoose: findOneAndUpdate doesn't return updated document mongoError: Topology was destroyed Difference between MongoDB and Mongoose How can you remove all documents from a collection with Mongoose? E11000 duplicate key error index in mongodb mongoose