Realice $ inc en el método de instancia, obtenga el documento actualizado

Tengo un método de instancia en Mongoose donde necesito realizar el operador $inc Mongo en un campo. Mi entendimiento es que, dado que v3, Mongoose no admite $inc de ninguna otra forma que no sea un método de actualización (por ejemplo, no hay un método de Mongoose para tomar un campo de objeto de documento de Mongoose y realizar $inc en él, luego llamar a save de una manera que evite condiciones de carrera)

La función de callback necesita un objeto de usuario actualizado con los cambios de actualización reflejados. Sin embargo, la actualización de esta manera no actualiza el documento original desde el cual estamos realizando el método de instancia. Sus campos de saldo y compras permanecen intactos.

 usersSchema.methods.completePurchase = function(item, incBalance, cb) { return this.update({ $addToSet: { "purchases": item }, $inc: { "balance": incBalance } }, function(err) { // I NEED THE UPDATED USER AT THIS POINT return cb(err); }); }; 

Como alternativa, he intentado llamar a findByIdAndUpdate en el propio modelo, que devuelve el documento actualizado. Luego, lo dejo al método de llamada para hacer algo útil con el objeto de usuario actualizado devuelto.

 usersSchema.methods.completePurchase = function(item, incBalance, cb) { var model; model = this.model(this.constructor.modelName); return model.findByIdAndUpdate(this._id, { $addToSet: { "purchases": item }, $inc: { "balance": incBalance } }, function(err, updatedUser) { // CRASHES BEFORE REACHING THIS POINT return cb(err, updatedUser); }); }; 

Pero haciendo esto resulta en el siguiente error

 project/node_modules/mongoose/node_modules/mquery/lib/utils.js:26 if (/ObjectI[dD]$/.test(obj.constructor.name)) { ^ RangeError: Maximum call stack size exceeded 

¿Cuál es la forma correcta de realizar una llamada $inc o $addToSet dentro de un método de instancia de Mongoose que hará que el documento actualizado sea accesible?

Esto parecería ser los droides que buscas:

 usersSchema.methods.completePurchase = (item, incBalance, cb) -> model = @model(@constructor.modelName, @schema) model.findByIdAndUpdate @_id, $addToSet: purchases: item $inc: balance: incBalance , cb 

O en JavaScript:

 usersSchema.methods.completePurchase = function(item, incBalance, cb) { var model = this.model(this.constructor.modelName, this.schema); return model.findByIdAndUpdate(this._id, { $addToSet: { purchases: item }, $inc: { balance: incBalance } }, cb); }; 

Y llamarías como (JavaScript, ¡lo siento!):

 user.completePurchase(item, incBalance function(err,doc) { // Something here }) 

O al menos eso funciona para mí.


Mi prueba


 var mongoose = require('mongoose'); var Schema = mongoose.Schema; mongoose.connect('mongodb://localhost/nodetest') var childSchema = new Schema({ name: 'string' }); var parentSchema = new Schema({ children: [childSchema] }); parentSchema.methods.findMe = function(cb) { return this.model(this.constructor.modelName, this.schema) .findById(this._id, cb); }; var Parent = mongoose.model('Parent', parentSchema); var parent = new Parent( { children: [{ name: 'Bart' }] }); parent.save(function(err,doc) { console.log( "saved: " + doc ); doc.findMe(function(err,doc2) { console.log( "found: " + doc2 ); }); });