Tengo un documento que necesita ser leído y actualizado. Mientras tanto, es bastante probable que otro proceso esté haciendo lo mismo, lo que interrumpiría la actualización del documento.
Por ejemplo, si el Proceso A lee el documento d y le agrega el campo 'a' y escribe el documento, y el Proceso B lee el documento d antes de que el Proceso A lo escriba, y agrega el campo b y escribe el documento, entonces el proceso que escribe los cambios recibirá su cambio porque anula el cambio del que escribió primero.
He leído este artículo y algunos otros artículos de transacciones muy complicados sobre mongo. ¿Alguien puede describir una solución simple para esto? Todavía no he encontrado algo que me haga sentir cómodo con esto.
https://www.mongodb.com/blog/post/how-to-select--for-update-inside-mongodb-transactions
[ACTUALIZAR] - Además, estoy tratando de aumentar un documento que quizás aún no exista. Necesito crear el documento si no existe. También necesito leerlo para analizarlo. Una clave es "relatedIds" (una matriz). Empujo a esa matriz si la identificación no se encuentra en ella. Otro método que tengo que necesita para crear el documento si no existe se agrega a una colección separada de objetos.
[OTRA ACTUALIZACIÓN x2] --> Por lo que he estado leyendo y obteniendo de varias fuentes, es que la única forma de crear correctamente una transacción para esto es "findOneAndModify" el documento para marcarlo como sucio con algún campo que definitivamente se actualizará, como "bloquear" con un objectId (ya que eso nunca dará como resultado un NO-OP, es decir, definitivamente causa un cambio).
Si otra operación intenta escribir en él, Mongo ahora puede detectar que este registro ya es parte de una transacción.
Por lo tanto, cualquier cosa que escriba en él provocará un error de escritura en esa otra operación. Mi transacción puede trabajar lentamente en ese registro y bloquearlo. Cuando lo escribe y se compromete, ese registro definitivamente no es tocado por nada más. Si no hay forma de hacer esto sin una transacción por alguna razón, ¿estoy creando la transacción de la manera más fácil aquí?
Usar las transacciones de Mongo es la forma "adecuada" de hacerlo, pero ofreceré una solución simple que es suficiente (con algunas advertencias).
La solución más simple sería usar findOneAndUpdate para leer el documento y actualizar un nuevo campo, llamémoslo status , ya que es atómico, esto es posible.
la consulta se vería así:
const doc = await db.collection.findOneAndUpdate( { _id: docId, status: { $ne: 'processing' } }, { $set: { status: 'processing' } } ); entonces, si dov.value es null , significa (asumiendo que el documento existe) que otro proceso lo está procesando. Cuando termine de procesar, solo necesita restablecer el status para que sea cualquier otro valor.
Ahora, debido a que está bloqueando inherentemente este documento para que no se lea hasta que finalice el proceso, debe asegurarse de manejar casos como un error durante el proceso, falla de actualización, problemas de conexión de db, etc.
En general, sería cauteloso al usar este enfoque, ya que solo "bloqueará" el documento para las consultas "adecuadas" (cada proceso debe actualizarse para usar el campo de status ), lo cual es un poco problemático, dependiendo de su caso de uso.