Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger a function whenever a mongoose document is updated

I have a user model schema in mongoose which contains a list of friends and groups and stats info like so...

var user = new Schema({
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true, select: false },
  roles: [{ type: String, required: true }],
  friends: [{ type: Schema.Types.ObjectId, ref: 'User' }],
  groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }], 
  stats : {
    nbrFriends: { type: Number, required: false },
    nbrGroups: { type: Number, required: false }
  }
}, {
  timestamps: true
}); 

I need to update the users stats whenever a change is made to the friends or groups fields to contain the new number of friends or groups etc. For example, when the following function is called on a user:

var addGroup = function(user, group, cb) {

  user.groups.push(group);
  User.findOneAndUpdate({ _id: user._id }, { $set: { groups: user.groups }}, { new: true }, function(err, savedResult) {
    if(err) {
      return cb(err);
    }
    console.log('updated user: ' + JSON.stringify(savedResult));
    return cb(null, savedResult);
  });
};

How could I make sure the stats is automatically updated to contain the new number of groups the user has? It seems like a middleware function would be the best approach here. I tried the following but this never seems to get called...

user.pre('save', function(next) {
  var newStats = {
    nbrGroups: this.groups.length,
    nbrPatients: this.friends.length
  };
  this.stats = newStats;
  this.save(function(err, result) {
    if(err) {
      console.log('error saving: ' + err);
    } else {
      console.log('saved');
    }
    next();
  });  
});
like image 484
CSharp Avatar asked Mar 30 '17 17:03

CSharp


2 Answers

You need to use the middleware a.k.a. hooks:

Middleware (also called pre and post hooks) are functions which are passed control during execution of asynchronous functions.

See the docs:

  • http://mongoosejs.com/docs/middleware.html
like image 97
rsp Avatar answered Nov 13 '22 12:11

rsp


From version 3.6, you can use change streams.

Like:

const Users = require('./models/users.js')

 var filter = [{
        $match: {
            $and: [{
                 $or:[
                { "updateDescription.updatedFields.friends": { $exists: true } },
                { "updateDescription.updatedFields.groups": { $exists: true } },
              ]
                { operationType: "update" }]
            }
        }];

 var options = { fullDocument: 'updateLookup' };


let userStream = Users.watch(filter,options)

userStream.on('change',next=>{

//Something useful!

})

like image 2
Pranesh A S Avatar answered Nov 13 '22 11:11

Pranesh A S