Estoy tratando de hacer una transacción con mangosta.
Cuando ejecuto el código, parece que el documento mongoose recuerda la sesión incluso después de llamar a await session.endSession() . Y luego, cuando llamo a .save() en ese documento, aparece el error "No se permite el uso de sesiones caducadas".
Esta es la demostración (solo un ejemplo simplificado):
const MessageSchema = new mongoose.Schema({ text: String }, {strict: 'throw'}); const Message = mongoose.model('Message', MessageSchema); const session = await mongoose.startSession(); let message; await session.withTransaction(async () => { message = (await Message.create([{text: 'My message'}], {session}))[0]; }); await session.endSession(); message.text = 'My message 2'; await message.save(); Ese .save() final está arrojando ese error. Si registrara message.$session().hasEnded , se volvería verdadero. Mi expectativa era que, si la sesión ha terminado, sería inteligente no usar .save().
Lo que quiero lograr: crear algunos documentos con transacción, confirmarlos, para que estén en la base de datos.
Luego, use ese mismo documento, que ya está en la base de datos, para hacerle algunos cambios.
¿Qué estoy haciendo mal aquí? ¿Cómo puedo evitar que .save() un error e intente usar una sesión caducada?
No hay secciones sobre endSession en ninguna parte de los documentos de mongoose , pero como muy bien lo descubrió usted mismo, cuando se llama a esta función, solo establece una marca para su objeto de session en lugar de destruirlo. Si se destruyó, tendría otro error.
Mi expectativa era que, si la sesión ha terminado, sería inteligente no usar .save().
De hecho, es lo suficientemente inteligente como para no usarlo, el marco solo le informa que está intentando una instrucción ilegal.
Lo que quiero lograr: crear algunos documentos con transacción, confirmarlos, para que estén en la base de datos.
Eso es exactamente lo que hace con su llamada withTransaction . Este contenedor lo ayuda a crear, confirmar y abortar/reintentar en caso de que suceda algo malo, por lo que después de esa llamada y si todo terminó bien, de hecho creó con éxito un documento en la base de datos.
Luego, use ese mismo documento, que ya está en la base de datos, para hacerle algunos cambios.
Depende de lo que entiendas por "más tarde". Si es parte del mismo punto final (y no sé por qué modificaría inmediatamente ese documento en lugar de confirmarlo correctamente en primer lugar), entonces, como dije en los comentarios, mover la llamada endSession probablemente solucionaría el problema:
const MessageSchema = new mongoose.Schema({ text: String }, {strict: 'throw'}); const Message = mongoose.model('Message', MessageSchema); const session = await mongoose.startSession(); let message; await session.withTransaction(async () => { message = (await Message.create([{text: 'My message'}], {session}))[0]; }); message.text = 'My message 2'; await message.save(); await session.endSession(); Si es parte de otro punto final, simplemente realice otra transacción como la que acaba de hacer, excepto que modifica el documento en lugar de crearlo. O si no necesita ninguna transacción, use un método como findOneAndUpdate o findByIdAndUpdate . Creo que parece estar lo suficientemente familiarizado con JS y Mongoose para hacerlo por su cuenta.
¿Qué estoy haciendo mal aquí?
Básicamente, no mucho. Ya entendiste que no puedes llamar a .save() después de finalizar una sesión.
¿Cómo puedo evitar que
.save()un error e intente usar una sesión caducada?
no puedes Es simplemente un recordatorio de que está intentando una operación ilegal. Sin embargo, puede intentar/atrapar el error y decidir no hacer nada al respecto en su cláusula de catch , O escribir una declaración if que verifique el message.$session().hasEnded .