2013-05-03 11 views
75

come dice il titolo, voglio eseguire un find (uno) per un documento, da _id, e se non esiste, farlo creare , quindi se è stato trovato o è stato creato, è stato restituito nel callback.MongoDB atomico "findOrCreate": findOne, inserire se inesistente, ma non aggiornare

Non voglio aggiornarlo se esiste, come ho letto findAndModify fa. Ho visto molte altre domande su Stackoverflow riguardo a questo, ma ancora una volta, non desidero aggiornare nulla.

Io sono sicuro se con la creazione (di non esistere), che in realtà è l'aggiornamento tutti ne parlano, è tutto così confuzzling :(

risposta

144

Cominciando con MongoDB 2.4, non è più necessario fare affidamento su un indice univoco (o di qualsiasi altra soluzione) per Atomic findOrCreate operazioni analoghe.

Questo è grazie a the $setOnInsert operator nuovo a 2.4, che consente di specificare gli aggiornamenti che dovrebbero verificarsi solo quando si inseriscono documenti.

Questo, combinato con l'opzione upsert, significa che è possibile utilizzare findAndModify per ottenere un'operazione analoga a findOrCreate.

db.collection.findAndModify({ 
    query: { _id: "some potentially existing id" }, 
    update: { 
    $setOnInsert: { foo: "bar" } 
    }, 
    new: true, // return new doc if one is upserted 
    upsert: true // insert the document if it does not exist 
}) 

Come $setOnInsert colpisce solo i documenti di essere inseriti, se viene trovato un documento esistente, si verificherà nessuna modifica. Se non esiste alcun documento, ne effettuerà uno in avanti con l'id specificato, quindi eseguirà il set solo dell'inserto. In entrambi i casi, il documento viene restituito.

+0

Il tuo codice è utilizzato nella shell mongodb, ma come usarlo nel codice node.js? – Gank

+0

Il mio codice non può inserire un nuovo database in node.js. – Gank

+2

@Gank se stai usando il driver mongodb nativo per il nodo la sintassi sarebbe più come 'raccolta.findAndModify ({_ id: 'theId'}, , {$ setOnInsert: {pippo: 'bar'}}, {nuovo: vero, upsert: vero}, callback) '. Vedi [i documenti] (http://mongodb.github.io/node-mongodb-native/api-generated/collection.html) – numbers1311407

5

E 'un po' sporca, ma si può semplicemente inserirlo.

assicurarsi che la chiave ha un indice univoco su di esso (se si utilizza il _id è ok, è già unico).

In questo modo, se l'elemento è già presente verrà restituito un'eccezione che si può prendere.

Se non è presente, la nuova d verrà inserito un documento.

Aggiornato: una spiegazione dettagliata di questa tecnica sul MongoDB Documentation

+0

ok, questa è una buona idea, ma per il valore pre-esistente restituirà un errore ma NON il valore stesso, giusto? – Discipol

+3

Questa è in realtà una delle soluzioni consigliate per sequenze di operazioni isolate (trovare quindi creare se non trovato, presumibilmente) http://docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations/ – numbers1311407

+0

@Discipol se vuoi eseguire una serie di operazioni atomiche, dovresti prima bloccare il documento, quindi modificarlo e alla fine rilasciarlo. Ciò richiederà più query, ma è possibile ottimizzare per lo scenario migliore e fare solo 1-2 query la maggior parte delle volte. vedere: http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/ – Madarco

0

Ecco quello che ho fatto (Rubino conducente MongoDB):

Sarà aggiornarlo se esiste, ed inserirla se non lo fa.

Problemi correlati