node.js - nodejs - MongoDB atomic "findOrCreate": findOne, insertar si no existe, pero no actualizar
nodejs mongoose (4)
como dice el título, quiero realizar un find (uno) para un documento, por _id, y si no existe, hacer que se cree, luego si fue encontrado o fue creado, lo devolvió en la devolución de llamada.
No quiero actualizarlo si existe, como he leído findAndModify. He visto muchas otras preguntas sobre Stackoverflow con respecto a esto, pero una vez más, no deseo actualizar nada.
No estoy seguro si al crear (de no existir), ESO en realidad es la actualización de la que todo el mundo está hablando, todo es muy confuso :(
Con el último controlador (> versión 2), utilizará findOneAndUpdate ya que findAndModify
quedó en desuso. El nuevo método toma 3 argumentos, el filter
, el objeto de update
(que contiene sus propiedades predeterminadas, que deben insertarse para un nuevo objeto) y las options
donde debe especificar la operación de inserción.
Usando la sintaxis de la promesa, se ve así:
const result = await collection.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$setOnInsert: { foo: "bar" },
},
{
returnOriginal: false,
upsert: true,
}
);
const newOrUpdatedDocument = result.value;
Está un poco sucio, pero puedes simplemente insertarlo.
Asegúrese de que la clave tenga un índice único (si usa _id está bien, ya es único).
De esta forma, si el elemento ya está presente, devolverá una excepción que puede capturar.
Si no está presente, se insertará el nuevo documento.
Actualizado: una explicación detallada de esta técnica en la documentación de MongoDB
Esto es lo que hice (controlador Ruby MongoDB):
$db[:tags].update_one({:tag => ''flat''}, {''$set'' => {:tag => ''earth'' }}, { :upsert => true })}
Se actualizará si existe, y lo insertará si no lo hace.
A partir de MongoDB 2.4, ya no es necesario depender de un índice único (o de ninguna otra solución alternativa) para operaciones como findOrCreate
atómico.
Esto es gracias al operador $setOnInsert
nuevo en 2.4, que le permite especificar actualizaciones que solo deberían ocurrir al insertar documentos.
Esto, combinado con la opción upsert
, significa que puede usar findAndModify
para lograr una operación similar a findOrCreate
atómica.
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
})
Como $setOnInsert
solo afecta a los documentos que se insertan, si se encuentra un documento existente, no se producirá ninguna modificación. Si no existe ningún documento, se levantará uno con el _id especificado, luego se realizará el conjunto de solo inserción. En ambos casos, el documento es devuelto.