Use the Convenient Transaction API
You can perform a transaction to run a series of operations that do not change any data until the entire transaction is committed. This usage example uses the Convenient Transaction API to perform a transaction.
Tip
See also:
To learn more about the performing transactions in the Node.js driver, see the Transactions guide.
The Node.js driver also provides the Core API to perform transactions. To learn more about the Core API, see the Use the Core API usage example.
Example
Consider a situation in which a customer purchases items from your shop. To record the purchase, your application must update your inventory and record the order information.
The following table describes the collections that store purchase data and how a purchase changes the data in each collection.
Collection | Operation | Description of the Change |
---|---|---|
orders | insert | Inserts a document that describes the order |
inventory | update | Updates the quantities of items available after a purchase |
Sample Data
The inventory
collection contains the
following documents:
{ item: "sunblock", qty: 85, price: 6.0 }, { item: "beach chair", qty: 30, price: 25.0 }
You store purchase records in the orders
collection of the
testdb
database. This collection is empty, as there have been no
purchases.
Implementation
The code example in this section demonstrates how to use the Convenient Transaction API to perform a multi-document transaction in a session. In this example, the transaction makes the changes needed when a customer purchases items from your shop.
This example code performs a transaction through the following actions:
Calls the
withSession()
method on the client to implicitly create the session and run the callback passed to it within the session.Calls the
withTransaction()
method on the session to create a transaction, run the callback passed to it, and commit the transaction. If the transaction fails, this method ends the transaction and returns an error message.Performs the following operations within the transaction:
Updates the
inventory
andorders
collections if there is sufficient inventory to fulfill the purchaseEnds the transaction and throws an exception if there isn't sufficient inventory for any item in the order
Returns a message acknowledging that the transaction committed successfully with a copy of the purchase record
Prints the return type of
withSession()
, which is either the error message or the acknowledgment that the transaction completed.
const txnResult = await client.withSession(async (session) => session .withTransaction(async (session) => { const invColl = client.db("testdb").collection("inventory"); const recColl = client.db("testdb").collection("orders"); let total = 0; 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 invColl.findOneAndUpdate( { item: item.item, qty: { $gte: item.qty }, }, { $inc: { qty: -item.qty } }, { session } ); if (inStock === null) { await session.abortTransaction(); return "Item not found or insufficient quantity."; } const subTotal = item.qty * inStock.price; total = total + subTotal; } // Create a record of the purchase const receipt = { date: new Date(), items: order, total: total, }; await recColl.insertOne(receipt, { session }); return ( "Order successfully completed and recorded!\nReceipt:\n" + JSON.stringify(receipt, null, 1) ); }, null) .finally(async () => await client.close()) ); console.log(txnResult);
Sample Orders and Transaction Results
This section describes the results of the transactions performed for two sample orders.
Sufficient inventory exists for the following order, so the transaction successfully completes:
{ item: "sunblock", qty: 3 }, { item: "beach chair", qty: 1 }
After passing this order to the example transaction code, the code outputs the following result:
Order successfully completed and recorded! Receipt: { "date": "2023-08-25T20:06:52.564Z", "items": [ { "item": "sunblock", "qty": 3 }, { "item": "beach chair", "qty": 1 } ], "total": 43, "_id": "..." }
In the inventory
collection, the quantity of
"sunblock"
is now 82
and the quantity of "beach chair"
is 29
. The orders
collection contains the record of the
purchase.
There is not sufficient inventory for the following order, so the driver ends the transaction:
{ item: "volleyball", qty: 1 }
After passing this order to the example transaction code, the code outputs the following result:
Item not found or insufficient quantity.
Since the driver ends the transaction, there are no changes to
the inventory
and orders
collections.
API Documentation
To learn more about any of the methods or types discussed in this usage example, see the following API Documentation: