2013-06-21 13 views
11

Mi piacerebbe avere un unico metodo che crea o aggiorna un documento per un criterio. Cercando e provando diverse tecniche come this one, ho trovato un _id null per il mio documento. L'utilizzo di findByIdAndUpdate ha un effetto simile.Mongoose findOneAndUpdate Upsert _id null?

vedo un documento inserito nella collezione, ma il campo _id è nullo:

exports.savePolicy = function (plcy, callback) { 
    console.log('priority is : ' + plcy.priority) 
    try { 
     var policy = new Policy(plcy); 
     var query = {_id: plcy._id}; //this may be null 
     var update = { 
      name: plcy.name || defaults.policyDefaults.name, 
      longDescription: plcy.longDescription || defaults.policyDefaults.longDescription, 
      shortDescription: plcy.shortDescription || defaults.policyDefaults.shortDescription, 
      priority: plcy.priority, colorHex: plcy.colorHex || defaults.policyDefaults.colorHex, 
      settings: plcy.settings || [], 
      parentPolicyId: plcy.parentPolicyId || null 
     } 

     Policy.findOneAndUpdate(query, update, {upsert: true}, function (err, data) { 
      callback(err, data); 
     }); 

    } catch (e) { 
     log.error('Exception while trying to save policy: ' + e.message); 
     callback(e, null); 
    } 

C'è qualcosa che può essere fatto per ottenere il _id di non essere nullo quando il suo non è un aggiornamento?

+0

hai mai capire questo? Stavo ricevendo lo stesso problema. Ho finito per controllare manualmente _id e poi chiamare findOneAndUpdate per un aggiornamento o create() per un nuovo record. – Trent

risposta

5

Ho avuto lo stesso problema e non riuscivo a trovare un modo per farlo funzionare. Ho finito per scrivere il mio metodo upsert in questo modo ....

var upsert = function(model, data, f){ 
    if (!data._id) { 
    model.create(data, f); 
    } else { 
    var id = data._id; 
    delete data._id; 
    model.findOneAndUpdate({_id: id}, data, f); 
    } 
} 

che mi permette di chiamarla per uno dei miei modelli con una riga di codice ...

upsert(Team, team, f); 

Ci potrebbe essere un modo migliore per farlo, ma questo funziona per me. Posso fare aggiornamenti e inserimenti e non ottengo un _id nullo su insert.

+0

Bene, puoi risolvere questo problema usando qualcosa del genere: Model.findOneAndUpdate ({_id: id || Mongoose.Types.ObjectId()}, {$ set: attrs}, {upsert: true, new: true}) –

11

null è un _id valore valido in MongoDB, quindi se non si desidera utilizzare in nuovi documenti è necessario assicurarsi che un valore null viene sostituito con un nuovo ObjectID in query:

var query = {_id: plcy._id}; 
if (!query._id) { 
    query._id = new mongoose.mongo.ObjectID(); 
} 

// the rest stays the same... 
+0

Utilizziamo ObjectIds per dedurre la data/ora di creazione. Non sarebbe meglio che gli ObjectId siano creati sul lato server invece dei client che li creano? – dhaundy

1

Sono non usando Mongoose, ma mi imbatto in un problema simile con MongoDB. Per l'azione Upsert quando è stato inserito un nuovo oggetto, MongoDB stava impostando null su _id.

mi stava chiamando:

findOneAndUpdate({my_id:'my_unique_id'}, obj, {upsert: true}) 

dove obj._id era undefined.

Il problema era che _id era presente nell'elenco delle chiavi Object.keys(obj). Ho scoperto che stavo assegnando obj._id = some_variable, dove some_variable era undefined e che stava causando _id in un elenco di chiavi.

ho applicato soluzione chiamando a destra prima upsert:

if (_.isUndefined(obj._id)) { 
    delete obj._id; 
} 
0

Grazie ad JohnnyHK per una risposta utile sopra.Mi si avvicinò con una battuta dal momento che è usato così di frequente:

query = args._id ? { _id: args._id } : { _id: new ObjectId() }; 

Essa si basa sulla seguente Richiede:

const ObjectId = require('mongodb').ObjectID;