2011-09-07 10 views
28

Vorrei usare findAndModify per incrementare atomicamente un campo, usando Mongoose.La Mongoose supporta il metodo `findAndModify` di Mongodb?

Tuttavia, il codice qui sotto lancia la "TypeError: Object # non ha un metodo 'findAndModify'": l'errore

// 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

Come per la documentazione MongoDB il findAndModify dovrebbe essere la seguente, Collection.prototype.findAndModify = function (query, sort, update, new_doc, remove_doc, function (err) { //}) Ma non funziona quando converti questo tipo di mangusta! Per favore, chiariscimi su questo! – Raja

+4

Nuova funzionalità aggiunta in v3: http://aaronheckmann.posterous.com/mongoose-v3-part-2-findandmodify – EvdB

+2

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

risposta

1

Io suggerirei di usare lo stile diretto comando mostrato nella parte inferiore della http://www.mongodb.org/display/DOCS/findAndModify+Command. Non ho familiarità con la mangusta per conoscere il metodo per eseguire un comando, ma tutti i driver forniscono un modo per farlo. Se la mangusta no, puoi farlo direttamente usando lo stile descritto nella parte superiore di http://www.mongodb.org/display/DOCS/Commands.

Detto questo, è necessario assicurarsi che si ha realmente bisogno e che findAndModifyupdate non fare quello che avete bisogno di fare. Per vedere cosa update è in grado di dare un'occhiata a http://www.mongodb.org/display/DOCS/Updating.

59

La funzionalità non è buona (leggi: affatto) documentata, ma dopo aver letto il codice sorgente, ho trovato la seguente soluzione.

Crea lo schema della raccolta.

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

Creare un metodo statico sullo schema che esporrà il metodo findAndModify della collezione del modello.

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

Crea il tuo modello.

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

trovare e modificare!

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

Bonus

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

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

e, naturalmente, è possibile aggiungere un metodo di incremento sull'istanza – furf

+3

come ottenere il valore restituito da findAndModify tramite questo metodo? –

+0

Suppongo, come con qualsiasi altro luogo, leggendolo dal secondo parametro all'interno del callback. – incarnate

3

ho avuto findAndModify a

  • upsert un contatore (creare e inizializzare se non esiste)
  • incrementare il contatore
  • Chiamare una richiamata con il valore incrementato

in una sola andata e ritorno DB utilizzando il seguente codice:

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

Effettuato l'incremento della versione di lavoro per 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); 
}; 

usare qualcosa di simile a questo:

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

Spero che qualcuno rivelarsi utile

+0

È stato utile, in effetti, ma FWIW alla fine ho trovato contatori basati su Redis. Molto più veloce e molto più facile. – incarnate

14
+1

Questi consentono solo il rilevamento di voci singole – Tom

+3

MongoDB ha la stessa limitazione (http://docs.mongodb.org/manual/reference/command/findAndModify/). – juanpaco

3

un sacco di risposte, ma trovo questa semplice soluzione.

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


}); 
4

Nella versione 3, il metodo mangusta findOneAndUpdate espone il funzionamento findAndModify di MongoDB. Funziona in questo modo:

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

Maggiori informazioni qui: http://aaronheckmann.tumblr.com/post/48943524629/mongoose-v3-part-2-findandmodify

0

semplicemente aggiungendo alla risposta furf che se si utilizza objectId nella query, MongoDB non sarà in grado di trovare il documento. Lo strato di mangusta si occupa di convertire l'id oggetto stringa Hex che si ottiene dai parametri di instradamento all'ID oggetto corretto.

per risolvere questo è necessario:

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


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

Prendendo la risposta di cui sopra da @furf, questa è la mia soluzione 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); 
    } 
}; 
Problemi correlati