web-dev-qa-db-fra.com

MongoDB atomic "findOrCreate": findOne, insérez-le s'il n'existe pas, mais ne mettez pas à jour

comme le titre l'indique, je souhaite effectuer une recherche (un) pour un document, par id, et s'il n'existe pas, le faire créer, puis, le trouver ou le créer, le renvoyer dans le rappel.

Je ne veux pas le mettre à jour s'il existe, comme j'ai déjà lu findAndModify. J'ai vu beaucoup d'autres questions sur Stackoverflow à ce sujet, mais encore une fois, je ne souhaite rien mettre à jour.

Je ne sais pas si en créant (ou non existant), C’est en fait la mise à jour dont tout le monde parle, c’est tellement confuzzling :(

96
Discipol

Depuis MongoDB 2.4, il n’est plus nécessaire de s’appuyer sur un index unique (ni sur aucune autre solution de contournement) pour les opérations de type atomique findOrCreate.

C’est grâce à l’opérateur $setOnInsert new en 2.4, qui vous permet de spécifier des mises à jour qui ne devraient se produire que lors de l’insertion de documents.

Ceci, combiné à l'option upsert, signifie que vous pouvez utiliser findAndModify pour réaliser une opération de type atomique 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
})

Comme $setOnInsert n'affecte que les documents en cours d'insertion, aucune modification ne sera apportée si un document existant est trouvé. Si aucun document n'existe, il en remontera un avec l'ID spécifié, puis effectuera le jeu d'insertion uniquement. Dans les deux cas, le document est renvoyé.

172
numbers1311407

C'est un peu sale, mais vous pouvez simplement l'insérer.

Assurez-vous que la clé a un index unique (si vous utilisez le _id c'est ok, c'est déjà unique).

Ainsi, si l'élément est déjà présent, il renverra une exception que vous pouvez intercepter.

S'il n'est pas présent, le nouveau document sera inséré.

Mise à jour: une explication détaillée de cette technique sur Documentation MongoDB

5
Madarco

En utilisant le dernier pilote (> version 2), vous utiliserez findOneAndUpdate as findAndModify est obsolète. La nouvelle méthode prend 3 arguments, le filter, l'objet update (qui contient vos propriétés par défaut, doit être inséré pour un nouvel objet) et options où vous devez spécifier l'opération upsert.

En utilisant la syntaxe de la promesse, cela ressemble à ceci:

const result = await collection.findOneAndUpdate(
  { _id: new ObjectId(id) },
  {
    $setOnInsert: { foo: "bar" },
  },
  {
    returnOriginal: false,
    upsert: true,
  }
);

const newOrUpdatedDocument = result.value;
2
hansmaad