Utilizar a Core API
Você pode executar uma transação para executar uma série de operações que não alteram nenhum dado até que toda a transação seja confirmada. Este exemplo de uso usa a Core API para executar uma transação.
Dica
Veja também:
Para saber mais sobre as transações que são executadas no driver Node.js , consulte o guia detransações .
O driver do Node.js também fornece a Convenient Transaction API para executar transação. Para saber mais sobre a API de transação conveniente, consulte o exemplo de uso da API de transação conveniente .
Exemplo
Considere uma situação em que um cliente compra itens da sua loja online. Para registrar a compra, seu aplicativo deve atualizar seu estoque e os pedidos do cliente. Seu aplicativo também precisa salvar os detalhes do pedido.
A tabela a seguir descreve as collection que armazenam dados de compra e como uma compra altera os dados em cada collection.
collection | (operação) | Descrição da alteração |
---|---|---|
orders | insert | Insere um documento que descreve o pedido |
customers | atualizar ou upsert | Anexa o _id do documento do pedido ao histórico de pedidos no documento do cliente |
inventory | update | Atualiza as quantidades de itens disponíveis após uma compra |
Dados de amostra
Os exemplos de código utilizam os seguintes dados de amostra no reconhecimento de data center do testdb
:
Documentos na coleção
customers
que descrevem clientes e seus pedidos anterioresDocumentos na coleção
inventory
que incluem quantidades e descrições de todos os itens
O seguinte documento está na collection customers
:
{ _id: 98765, orders: [] }
A coleção inventory
contém os seguintes documentos:
{ item: "sunblock", item_id: 5432, qty: 85 }, { item: "beach towel", item_id: 7865, qty: 41 }
Você armazena registros de compra na collection orders
do reconhecimento de data center testdb
. Esta collection está vazia, pois não houve compras.
Os exemplos de código usam as variáveis cart
e payment
para representar uma lista de amostra de itens comprados e os detalhes de pagamento do pedido. O seguinte código descreve o conteúdo das variáveis cart
e 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 };
Implementação
O exemplo de código nesta seção demonstra como usar a Core API para realizar uma transação de vários documentos em uma sessão. Neste exemplo, a transação faz as alterações necessárias quando um cliente compra itens da sua loja.
Este código de exemplo executa uma transação por meio da seguinte ação:
Chama o método
startSession()
para criar uma nova sessãoChama o método
startTransaction()
com um parâmetro de opções para criar uma nova transaçãoExecuta as seguintes operações dentro da transação:
Insere um documento na collection
orders
que contém informações sobre a compra e o clienteAtualiza a collection
inventory
se houver estoque suficiente para atender à compraEncerra a transação e lança uma exceção se não houver estoque suficiente para qualquer item no pedido
Adiciona a ID do pedido à lista de pedidos anteriores para o cliente
Retorna uma mensagem reconhecendo que a transação foi confirmada com sucesso com uma cópia do registro de compra
Chama o método
commitTransaction()
para confirmar a transação se todas as operações forem concluídas com sucessoImplementa um bloco
catch
que contém lógica de tratamento de errosChama o método
abortTransaction()
para encerrar a transaçãoChama o método
endSession()
para encerrar a sessão
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(); } }
Resultados da transação
Esta seção descreve as alterações de dados criadas pela transação.
A collection customers
contém o documento do cliente com um pedido _id
anexado ao campo pedidos:
{ "_id": 98765, "orders": [ "61dc..." ] }
A collection inventory
contém quantidades atualizadas para os itens "sunblock"
e "beach towel"
:
[ { "_id": ..., "item": "sunblock", "item_id": 5432, "qty": 84 }, { "_id": ..., "item": "beach towel", "item_id": 7865, "qty": 39 } ]
A collection orders
contém as informações do pedido e do pagamento:
[ { "_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 } ]
Documentação da API
Para saber mais sobre qualquer um dos métodos ou tipos discutidos neste exemplo de uso, consulte a seguinte documentação da API: