Puede ejecutar una transacción para ejecutar una serie de operaciones que no cambian los datos hasta que se confirme completamente la transacción. Este ejemplo de uso utiliza la Core API para realizar una transacción.
Tip
Para obtener más información sobre la realización de transacciones en el controlador Node.js, consulte Transactions guide.
El controlador de Node.js también proporciona la API de Transacciones Convenientes para realizar transacciones. Para obtener más información sobre la API de transacciones conveniente, consulta el ejemplo de uso de Usa la API de transacciones conveniente.
Ejemplo
Considera una situación en la que un cliente compra artículos en tu tienda en linea. Para registrar la compra, tu aplicación debe actualizar tu inventario y los pedidos de los clientes. Tu aplicación también debe guardar los detalles del pedido.
La siguiente tabla describe las colecciones que almacenan datos de compra y cómo una compra modifica los datos en cada colección.
Colección | Operación | Descripción del cambio |
|---|---|---|
| insert | Inserta un documento que describe el pedido. |
| actualizar o inserción | Añade el |
| update | Actualiza las cantidades de artículos disponibles después de una compra. |
Datos de muestra
Los ejemplos de código usan los siguientes datos de muestra en la base de datos testdb:
Documentos de la colección
customersque describen a los clientes y sus pedidos anterioresDocumentos en la colección
inventoryque incluyen cantidades y descripciones de todos los artículos
El siguiente documento está en la colección customers:
{ _id: 98765, orders: [] }
La colección inventory contiene los siguientes documentos:
{ item: "sunblock", item_id: 5432, qty: 85 }, { item: "beach towel", item_id: 7865, qty: 41 }
Almacena los registros de compra en la colección orders de la base de datos testdb. Esta colección está vacía, ya que no se han realizado compras.
Los ejemplos de código utilizan las variables cart y payment para representar una lista de muestra de artículos comprados y los detalles de pago del pedido. El código siguiente describe el contenido de las variables cart y payment:
const cart = [ { item: 'sunblock', item_id: 5432, qty: 1, price: 5.19 }, { item: 'beach towel', item_id: 7865, qty: 2, price: 15.99 } ]; const payment = { customer: 98765, total: 37.17 };
implementación
El ejemplo de código en esta sección demuestra cómo utilizar la Core API para realizar una transacción con múltiples documentos en una sesión. En este ejemplo, la transacción realiza los cambios necesarios cuando un cliente adquiere artículos en tu tienda.
Este código de ejemplo realiza una transacción mediante las siguientes acciones:
Llama al método
startSession()para crear una nueva sesiónLlama al método
startTransaction()con un parámetro de opciones para crear una nueva transacciónRealiza las siguientes operaciones dentro de la transacción:
Inserta un documento en la colección
ordersque contiene información sobre la compra y el clienteActualiza la colección
inventorysi hay suficiente inventario para completar la compraTermina la transacción y lanza una excepción si no hay suficiente inventario para algún artículo del pedido.
Agrega el ID del pedido a la lista de pedidos anteriores del cliente
Devuelve un mensaje reconociendo que la transacción se completó correctamente con una copia del registro de compra
Llama al método
commitTransaction()para confirmar la transacción si todas las operaciones se completan correctamenteImplementa un bloque
catchque contiene lógica de manejo de erroresLlama al método
abortTransaction()para finalizar la transacciónLlama al método
endSession()para finalizar la sesión
async function placeOrder(client, cart, payment) { const transactionOptions = { readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' }, readPreference: 'primary' }; // Start the session const session = client.startSession(); try { // Start the transaction in the session, specifying the transaction options session.startTransaction(transactionOptions); const ordersCollection = client.db('testdb').collection('orders'); /* Within the session, insert an order that contains information about the customer, items purchased, and the total payment */ const orderResult = await ordersCollection.insertOne( { customer: payment.customer, items: cart, total: payment.total, }, { session } ); const inventoryCollection = client.db('testdb').collection('inventory'); for (const item of order) { /* Update the inventory for the purchased items. End the transaction if the quantity of an item in the inventory is insufficient to complete the purchase. */ const inStock = await inventoryCollection.findOneAndUpdate( { item_id: item.item_id, item_id: { $gte: item.qty } }, { $inc: { 'qty': -item.qty }}, { session } ) if (inStock === null) { throw new Error('Insufficient quantity or item ID not found.'); } } const customerCollection = client.db('testdb').collection('customers'); // Within the session, add the order details to the "orders" array of the customer document await customerCollection.updateOne( { _id: payment.customer }, { $push: { orders: orderResult.insertedId }}, { session } ); // Commit the transaction to apply all updates performed within it await session.commitTransaction(); console.log('Transaction successfully committed.'); } catch (error) { /* Handle any exceptions thrown during the transaction and end the transaction. Roll back all the updates performed in the transaction. */ if (error instanceof MongoError && error.hasErrorLabel('UnknownTransactionCommitResult')) { // Add your logic to retry or handle the error } else if (error instanceof MongoError && error.hasErrorLabel('TransientTransactionError')) { // Add your logic to retry or handle the error } else { console.log('An error occured in the transaction, performing a data rollback:' + error); } await session.abortTransaction(); } finally { // End the session await session.endSession(); } }
Tip
Gestión explícita de recursos
El driver de Nodo.js admite nativamente la gestión explícita de recursos para MongoClient, ClientSession, ChangeStreams y cursores. Esta funcionalidad es experimental y está sujeta a cambios. Para aprender a usar la gestión explícita de recursos, consulta el Notas de versión v6.9.
Resultados de la transacción
Esta sección describe los cambios de datos creados por la transacción.
La colección customers contiene el documento del cliente con un pedido _id añadido al campo de pedidos:
{ "_id": 98765, "orders": [ "61dc..." ] }
La colección inventory contiene cantidades actualizadas para los artículos "sunblock" y "beach towel":
[ { "_id": ..., "item": "sunblock", "item_id": 5432, "qty": 84 }, { "_id": ..., "item": "beach towel", "item_id": 7865, "qty": 39 } ]
La colección orders contiene la información del pedido y el pago:
[ { "_id": "...", "customer": 98765, "items": [ { "item": "sunblock", "item_id": 5432, "qty": 1, "price": 5.19 }, { "item": "beach towel", "item_id": 7865, "qty": 2, "price": 15.99 } ], "total": 37.17 } ]
Documentación de la API
Para obtener más información sobre cualquiera de los métodos o tipos tratados en este ejemplo de uso, consulta la siguiente Documentación de la API: