2011-09-07 16 views
28

Me gustaría utilizar findAndModify para incrementar atómicamente un campo, usando Mongoose.¿Mongoose es compatible con el método `findAndModify` de Mongodb?

Sin embargo, el código de abajo lanza el "TypeError: Objeto # tiene ningún método 'findAndModify'": error

// defining schema for the "counters" table 
var tableSchema = new Schema({ 
    _id: String, 
    next: Number   
}); 

// creating table object for the counters table 
var counters_table = mongoose.model('counters', tableSchema); 
var tableObj = new counters_table();  

// increment the "next" field on the table object 
var query = {_id: 'messagetransaction'}; 
var update = {'$inc': {next: 1}}; 
var ret = tableObj.findAndModify(query, [], update, true, true, function(err) { 
    if (err) { 
     throw err; 
    } 
    else { 
     console.log("updated!"); 
    } 
}); 
+0

De acuerdo con la documentación mongodb la findAndModify debe ser el siguiente, Collection.prototype.findAndModify = function (query, sort, update, new_doc, remove_doc, function (err) { //}) ¡Pero no funciona cuando lo convierto en mangosta! Por favor, aclarame sobre esto! – Raja

+4

Nueva función añadida en v3: http://aaronheckmann.posterous.com/mongoose-v3-part-2-findandmodify – EvdB

+2

Mongoose v3 documentos: [findOneAndUpdate] (http://mongoosejs.com/docs/api.html#query_Query -findOneAndUpdate) o [findOneAndRemove] (http://mongoosejs.com/docs/api.html#model_Model.findOneAndRemove) – aaronheckmann

Respuesta

1

se recomienda usar el estilo de mando directo se muestra en la parte inferior de http://www.mongodb.org/display/DOCS/findAndModify+Command. No estoy lo suficientemente familiarizado con la mangosta para conocer el método para ejecutar un comando, pero todos los controladores proporcionan alguna forma de hacerlo. Si la mangosta no lo hace, puede hacerlo directamente utilizando el estilo descrito en la parte superior de http://www.mongodb.org/display/DOCS/Commands.

Dicho esto, debe asegurarse de que realmente necesita findAndModify y que update no hará lo que necesita hacer. Para ver qué update es capaz de echar un vistazo a http://www.mongodb.org/display/DOCS/Updating.

59

La característica no está bien (léase: en absoluto) documentada, pero después de leer el código fuente, se me ocurrió la siguiente solución.

Cree su esquema de colección.

var Counters = new Schema({ 
    _id: String, 
    next: Number  
}); 

crear un método estático en el esquema que expondrá el método findAndModify de la colección del modelo.

Counters.statics.findAndModify = function (query, sort, doc, options, callback) { 
    return this.collection.findAndModify(query, sort, doc, options, callback); 
}; 

Crear su modelo.

var Counter = mongoose.model('counters', Counters); 

Buscar y modificar!

Counter.findAndModify({ _id: 'messagetransaction' }, [], { $inc: { next: 1 } }, {}, function (err, counter) { 
    if (err) throw err; 
    console.log('updated, counter is ' + counter.next); 
}); 

Bono

Counters.statics.increment = function (counter, callback) { 
    return this.collection.findAndModify({ _id: counter }, [], { $inc: { next: 1 } }, callback); 
}; 

Counter.increment('messagetransaction', callback); 
+1

y, por supuesto, puede agregar un método de incremento en la instancia – furf

+3

cómo obtener el valor de retorno de findAndModify a través de ¿este método? –

+0

Supongo, como en cualquier otro lugar, leyéndolo desde el segundo parámetro dentro de tu devolución de llamada. – incarnate

3

llegué a findAndModify

  • Upsert un contador (crear e inicializar si no existe)
  • incrementar el contador
  • Llamar a una devolución de llamada con el valor incrementado

en una sola ida y vuelta DB usando el siguiente código:

var Counters = new Schema({ 
    _id:String, // the schema name 
    count: Number 
}); 

Counters.statics.findAndModify = function (query, sort, doc, options, callback) { 
    return this.collection.findAndModify(query, sort, doc, options, callback); 
}; 

var Counter = mongoose.model('Counter', Counters); 

/** 
* Increments the counter associated with the given schema name. 
* @param {string} schemaName The name of the schema for which to 
* increment the associated counter. 
* @param {function(err, count)} The callback called with the updated 
* count (a Number). 
*/ 
function incrementCounter(schemaName, callback){ 
    Counter.findAndModify({ _id: schemaName }, [], 
    { $inc: { count: 1 } }, {"new":true, upsert:true}, function (err, result) { 
     if (err) 
     callback(err); 
     else 
     callback(null, result.count); 
    }); 
} 

Enjoy! - Curran

14

Incremento de la versión de trabajo hecha para Mongoose 3.x

var mongoose = require('mongoose'); 

var CounterSchema = new mongoose.Schema({ 
    _id: String, 
    next: {type: Number, default: 1} 
}); 

CounterSchema.statics.increment = function (counter, callback) { 
    return this.findByIdAndUpdate(counter, { $inc: { next: 1 } }, {new: true, upsert: true, select: {next: 1}}, callback); 
}; 

usar algo como esto:

Counter.increment('photo', function (err, result) { 
    if (err) { 
     console.error('Counter on photo save error: ' + err); return; 
    } 
    photo.cid = result.next; 
    photo.save(); 
}); 

espero que alguien vendrá bien

+0

Fue muy útil, de hecho, pero FWIW eventualmente creé contadores basados ​​en Redis. Mucho más rápido y mucho más fácil. – incarnate

14
+1

Estos solo permiten encontrar entradas individuales – Tom

+3

MongoDB tiene la misma limitación (http://docs.mongodb.org/manual/reference/command/findAndModify/). – juanpaco

3

muchas respuestas pero me parece una solución tan simple.

Counter.findByIdAndUpdate(ID, {$inc: {next:1}}, function (err, data) { 


}); 
4

En la versión 3, el método mangosta findOneAndUpdate expone operación findAndModify de mongodb. Funciona de la siguiente manera:

var query = { name: 'Sprinkls' }; 
var update = { name: 'Sprinkles' }; 
var options = { new: false }; 
Cat.findOneAndUpdate(query, update, options, function (err, cat) { 
    if (err) .. 
    render('cat', cat); 
}); 

Más información aquí: http://aaronheckmann.tumblr.com/post/48943524629/mongoose-v3-part-2-findandmodify

0

sólo añadir a la respuesta furf que si utiliza objectId en la consulta, MongoDB no será capaz de encontrar el documento. La capa de mangosta se encarga de convertir el Id. De objeto de cadena hexadecimal que obtienes de los parámetros de enrutamiento al id de objeto adecuado.

para resolver esto es necesario:

var ObjectID = require('mongodb').ObjectID; 


var itemId = req.params.itemId; 
var objectId = ObjectID.createFromHexString(itemId); 
Item.findAndModify({_id: objectId}, 
1

Tomando la respuesta por encima de @furf, esto es mi solución promised:

// eslint-disable-next-line func-names 
localeTypesSchema.statics.findAndModify = function (query, sort, update, opts, callback) { 
    const cb = callback || (() => { }); 
    try { 
     const result = this.collection.findAndModify(query || {}, sort || [], update || {}, opts); 
     cb(null, result); 
     return Promise.resolve(result); 
    } catch (err) { 
     cb(err); 
     return Promise.reject(err); 
    } 
}; 
Cuestiones relacionadas