it-swarm.com.de

Wie kann ich in Mongoose erstellen/finden?

Manchmal muss ein Dokument in der Datenbank vorhanden sein, und ich bin froh, entweder mit dem vorhandenen Dokument zu arbeiten oder das Dokument zu erstellen, wenn es fehlt, und mit dem neuen zu arbeiten.

Dies scheint ein recht häufiger Anwendungsfall zu sein, aber ich habe die Mongoose-Dokumente durchgesehen und kann nichts finden.

Bei Mongoose Collection-Methoden wie findOneAndUpdate() und update() mit upsert: true geht es um das Ändern von Dokumenten. Ich möchte das Dokument nicht ändern, wenn es vorhanden ist, sondern nur einen Verweis darauf abrufen.

Beispiel : (hinzugefügt für @neillunn) Ich möchte einen Benutzer mit einem Verweis auf eine Firma hinzufügen, deren 'Name' 'foo' ist. Vorher würde ich gerne eine Firma mit {name: 'foo'} suchen und diese erstellen, wenn sie nicht existiert.

Beispiel 2 : (für @neillunn hinzugefügt) Code, den ich jetzt verwende, um das Beispielszenario zu behandeln:

// Find or create an an instance and return a cb with a reference to it.
var findOrCreate = function(model, criteria, cb){
    model.update(criteria, criteria, {upsert: true}, function(err, numberAffected, raw){
        if ( ! raw.updatedExisting ) {
            console.log('Created instance')
        } else {
            console.log('Found existing instance')
        }           
        model.findOne(criteria, cb)
    })
}

Hinweis : findOneAndUpdate() funktioniert nicht, da versucht wird, das vorhandene Dokument zu ändern, und ein 'Index für doppelte Schlüsselfehler' abgerufen wird.

12
mikemaccana

Wie in den Kommentaren angegeben, gibt es ein Plugin für Mungo, das dies tut: http://github.com/drudge/mongoose-findorcreate

Dieser Thread beschreibt auch einen Weg, dies ohne Plugin zu erreichen. Ich bin mir nur nicht sicher, ob es mit Mungo funktioniert.

11
Charminbear

Mongoose hat eine eingebaute findOneAndUpdate Funktion kann finden und wenn die Daten nicht existieren, werden die Daten erstellt. Grundsätzlich ist unten, wie es gemacht wird:

var modelDoc = new MyModel({ foo: 'bar' });

MyModel.findOneAndUpdate(
    {foo: 'bar'}, // find a document with that filter
    modelDoc, // document to insert when nothing was found
    {upsert: true, new: true, runValidators: true}, // options
    function (err, doc) { // callback
        if (err) {
            // handle error
        } else {
            // handle document
        }
    }
);

Der Parameter options ist wichtig, damit die Einfügung funktioniert.`

Durch Festlegen von upsert: true weisen Sie MongoDB an, das modelDoc-Dokument tatsächlich der Sammlung hinzuzufügen, wenn der {foo: 'bar'}filter kein Ergebnis gefunden hat.

Die Option new: true ändert, was in der Rückruffunktion zurückgegeben wird. Wenn es falsch ist, enthält doc das Dokument vor dem Aktualisieren (oder null vor dem Einfügen). Wenn dies zutrifft, enthält doc das Dokument nach dem Aktualisieren oder Erstellen. Zwar ist false die Standardoption, aber ich denke, die meisten Leute würden es tatsächlich vorziehen, wenn es wahr wäre.

Die Option runValidators: true muss gesetzt sein, wenn Mongoose die Validatoren ausführen soll. Standardmäßig werden diese bei Verwendung von findOneAndUpdate() nicht ausgeführt.

1
imin

Sehr nützliche Lösung hier: https://stackoverflow.com/a/7592756/4025963 :

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

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

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

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

Noch interessanter, wenn es um Versprechen geht:

Counters.statics.findAndModify =
    function findAndModify(query, sort, update, options, callback) {
        const promised = q.nbind(this.collection.findAndModify, this.collection);
        return promised(query || {}, sort || [], update || {}, options, callback);
    };
1
David