Dan Tang
Dan Tang

Reputation: 1333

Updating values in mongodb

I have a mongodb model called User, which has a mixed schema type variable called "inventory" (contains all the items a user contains). I would like to loop through all the users, and change the name of each item in their inventory. In particular, I would like to convert strings in the format of "10_alex_magician" or "3_maia_princess" to "alex_magician" and "maia_princess" respectively. The string conversion is relatively straightforward, and I'm using x.split('').slice(1).join('') to accomplish the conversion.

Where I'm having trouble is even when console.log shows that the conversion has been applied, it doesn't seem to be updating correctly to mongodb, yet no error message is being thrown. Does anyone know how to solve this?

Node.js function

//function to change old naming of items "10_alex_magician" to "alex_magician"
function modifyUser() {
  User.find({}, function(err, results) {
    _.map(results, function(result) {
      var regex = /^\d+_[A-Za-z]+_[A-Za-z]+$/
      for (var i = 0, len = result.inventory.length; i < len; i++) {
        if(regex.test(result.inventory[i].itemName)) {
          result.inventory[i].itemName = result.inventory[i].itemName.split('_').slice(1).join('_');  
          result.save(function(err, r) {
            if(err) console.log(err);
            //logging r shows that the text has been correctly updated
            console.log(r)
          });

        }
      }       
    })
  })
}

Format of inventory variable

"inventory": [
      {
        "type": "sticker",
        "numberOwned": 2,
        "itemName": "1_alex_magician"
      },
      {
        "type": "sticker",
        "numberOwned": 1,
        "itemName": "10_alex_scuba"
      }
    ],

Upvotes: 0

Views: 189

Answers (1)

Peter Lyons
Peter Lyons

Reputation: 145994

Mongoose only has automatic change detection for top-level properties and you are modifying a nested property, so mongoose doesn't know anything changed. Use markModified to tell mongoose you are mucking with inventory.

result.inventory[i].itemName = result.inventory[i].itemName.split('_').slice(1).join('_');
result.markModified('inventory');
result.save(....)

For efficiency, you may want to consider both .lean() and .stream() for this type of query and just do your updates with findByIdAndUpdate, passing just the updated inventory property.

Upvotes: 1

Related Questions