Puede realizar una transacción para ejecutar una serie de operaciones que no modifican ningún dato hasta que se confirme toda la transacción. Este ejemplo de uso utiliza la API principal para realizar una transacción.
Tip
Para obtener más información sobre la realización de transacciones en el controlador Node.js, consulte Guía de transacciones.
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 Convenientes, consulte el ejemplo de uso de la API de Transacciones Convenientes.
Ejemplo
Imaginemos una situación en la que un cliente compra artículos en su tienda online. Para registrar la compra, la aplicación debe actualizar el inventario y los pedidos del cliente. También debe guardar los detalles del pedido.
La siguiente tabla describe las colecciones que almacenan datos de compra y cómo una compra cambia los datos en cada colección.
Colección | Operación | Descripción del cambio |
|---|---|---|
| insert | Inserta un documento que describe el pedido. |
| actualizar o insertar | Añade el |
| update | Actualiza las cantidades de artículos disponibles después de una compra. |
Datos de muestra
Los ejemplos de código utilizan los siguientes datos de muestra en la base de datos testdb:
Documentos de la colección
customersque describen a los clientes y sus pedidos anterioresDocuments in the
inventorycollection that include quantities and descriptions de all 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 ejemplo de artículos comprados y los detalles de pago del pedido. El siguiente código 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 };
Aplicación
El ejemplo de código de esta sección muestra cómo usar la API principal para realizar una transacción multidocumento en una sesión. En este ejemplo, la transacción realiza los cambios necesarios cuando un cliente compra artículos en su tienda.
Este código de ejemplo realiza una transacción a través de 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 cliente.Actualiza la colección
inventorysi hay suficiente inventario para completar la compraFinaliza la transacción y lanza una excepción si no hay suficiente inventario para algún artículo en el pedido
Agrega el ID del pedido a la lista de pedidos anteriores del cliente
Devuelve un mensaje que reconoce que la transacción se realizó 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 controlador Node.js admite de forma nativa la gestión explícita de recursos para MongoClient, ClientSession, ChangeStreams y cursores. Esta función es experimental y está sujeta a cambios. Para aprender a usar la gestión explícita de recursos, consulte Notas de la 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 del 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 analizados en este ejemplo de uso, consulte la siguiente documentación de API: