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í.
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 ); }); });