Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js Mongoose .update with ArrayFilters

As it stands, I am able to get this functionality working using the Mongo shell, but having issues with the nested arrays inside of Node.js using Mongoose.

Mongo shell command that is successful:

db.test.update({}, {$set: {"this.$[i].that.$[x].amnt": 10000}}, {arrayFilters: [{"i._id": ObjectId('5a568059bc44142a9ca33d09')}, {"x.userId": ObjectId('5a466acb864c752f8c9890c6')}]})

Result: changed the amnt field to 10000. There was no matches returned until calling ObjectId('') on the given strings pulled from the database.

Node.js code:

var conditions = {}
var update = {$set: {"this.$[i].that.$[x].amnt": 1000}
var options = {arrayFilters: [{"i._id": weekId}, {"x.userId":  r.userId}]}

myModel.update(conditions, update, options, function(err, rowsAffected){
    // handler 
}

Result: { ok: 0, n: 0, nModified: 0 }

_id and userId are schema.Types.ObjectId in the schema for the model.

I tried updating the node_modules/mongodb with the latest files for 3.6.1. It appears mongoose uses 3.0.1. Printing out to console typeof(weekId) or typeof(r.userId) shows type of string. I believe this gets changed based on the schema, but either way I tried calling mongoose.Types.ObjectId(weekId) on these items to see if this resolved it, but no luck.

MongoDB: 3.6.1 Mongoose: 5.0.0-rc2

like image 367
Justin Breed Avatar asked Jan 11 '18 20:01

Justin Breed


2 Answers

I don't know if Mongoose 5.0.0 is supposed to support Arrayfilters out of the box but you can achieve it by using Mongoose's command-method which directly executes on MongoDB, hence can utilize all features available which includes ArrayFilters on MongoDB 3.6.1

Example:

mongoose.connection.db.command({
  update: <YourModel>.collection.name,
  updates: [
    {
      q: { 'field1.field2._id': mongoose.Types.ObjectId(<someObjectid>) },
      u: {
        $set: { 'field1.$.field2.$[field].fieldToUpdate': "updated!" },
      },
      arrayFilters: [
        { 'field._id': mongoose.Types.ObjectId(<someObjectid>) },
      ],
    },
  ],
})
like image 176
actraiser Avatar answered Sep 23 '22 14:09

actraiser


I tried it using the mongoose v5.0.14 and it works fine with MongoDB 3.6.3 version!

This is my package.json...

"dependencies": {
  "mongoose": "^5.0.14",
}

This is my update function with arrayFilters...

...

// my id variable
let id = "5ad1f4dec48d7e156034c156";

// mongo condition
let mc = {_id: id};

// mongo dataset
let ds = {'contacts.$[i].main': false};

// mongo options
let op = {                             
  arrayFilters: [
    {
      $and: [
        {'i._id': {$ne: id}},
        {'i.type': 'mobile'},
      ],
    }],
};

<<Model>>.findOneAndUpdate(mc, ds, op, (err, doc) => {
  callback(err, doc);
});

...
like image 40
Biruel Rick Avatar answered Sep 23 '22 14:09

Biruel Rick