|
| 1 | +.. _session-withTransaction: |
| 2 | + |
| 3 | +========================== |
| 4 | +Session.withTransaction() |
| 5 | +========================== |
| 6 | + |
| 7 | +.. default-domain:: mongodb |
| 8 | + |
| 9 | +.. contents:: On this page |
| 10 | + :local: |
| 11 | + :backlinks: none |
| 12 | + :depth: 1 |
| 13 | + :class: singlecol |
| 14 | + |
| 15 | +Definition |
| 16 | +---------- |
| 17 | + |
| 18 | +.. method:: Session.withTransaction( <function> [, <options> ] ) |
| 19 | + |
| 20 | + *New in mongosh v1.1.0* |
| 21 | + |
| 22 | + Runs a specified lambda function within a transaction. If there is an |
| 23 | + error, the method retries the: |
| 24 | + |
| 25 | + - commit operation, if there is a failure to commit. |
| 26 | + - entire transaction, if the error permits. |
| 27 | + |
| 28 | + The :method:`Session.withTransaction()` method accepts the |
| 29 | + `transaction options |
| 30 | + <https://mongodb.github.io/node-mongodb-native/4.8/interfaces/TransactionOptions.html>`__. |
| 31 | + |
| 32 | + |
| 33 | +Behavior |
| 34 | +-------- |
| 35 | + |
| 36 | +The Node.js driver has a version of ``Session.withTransaction()` that is |
| 37 | +known as the `Callback API |
| 38 | +<https://www.mongodb.com/docs/drivers/node/current/fundamentals/transactions/#callback-api>`__. |
| 39 | +The ``Callback API`` also accepts an callback, however the return type |
| 40 | +for the Node.js method must be a Promise. The ``mongosh`` |
| 41 | +``Session.withTransaction()`` method does not require a Promise. |
| 42 | + |
| 43 | +Example |
| 44 | +------- |
| 45 | + |
| 46 | +The following example creates the ``balances`` collection and uses a |
| 47 | +transaction to transfer money between two customers. |
| 48 | + |
| 49 | +Create the ``balances`` collection: |
| 50 | + |
| 51 | +.. code-block:: javascript |
| 52 | + |
| 53 | + use accounts |
| 54 | + db.balances.insertMany( [ |
| 55 | + { customer: "Pat", balance: Decimal128( "35.88" ) }, |
| 56 | + { customer: "Sasha", balance: Decimal128( "5.23" ) } |
| 57 | + ] ) |
| 58 | + |
| 59 | + |
| 60 | +Initialize some variables that are used in the transaction: |
| 61 | + |
| 62 | +.. code-block:: javascript |
| 63 | + |
| 64 | + var fromAccount = "Pat" |
| 65 | + var toAccount = "Sasha" |
| 66 | + var transferAmount = 1 |
| 67 | + |
| 68 | + var dbName = "accounts" |
| 69 | + var collectionName = "balances" |
| 70 | + |
| 71 | +Start a session, then run a transaction to update the accounts: |
| 72 | + |
| 73 | +.. code-block:: javascript |
| 74 | + |
| 75 | + var session = db.getMongo().startSession( { readPreference: { mode: "primary" } } ); |
| 76 | + session.withTransaction( async() => { |
| 77 | + |
| 78 | + const sessionCollection = session.getDatabase(dbName).getCollection(collectionName); |
| 79 | + |
| 80 | + // Check needed values |
| 81 | + var checkFromAccount = sessionCollection.findOne( |
| 82 | + { |
| 83 | + "customer": fromAccount, |
| 84 | + "balance": { $gte: transferAmount } |
| 85 | + } |
| 86 | + ) |
| 87 | + if( checkFromAccount === null ){ |
| 88 | + throw new Error( "Problem with sender account" ) |
| 89 | + } |
| 90 | + |
| 91 | + var checkToAccount = sessionCollection.findOne( |
| 92 | + { "customer": toAccount } |
| 93 | + ) |
| 94 | + if( checkToAccount === null ){ |
| 95 | + throw new Error( "Problem with receiver account" ) |
| 96 | + } |
| 97 | + |
| 98 | + // Transfer the funds |
| 99 | + sessionCollection.updateOne( |
| 100 | + { "customer": toAccount }, |
| 101 | + { $inc: { "balance": transferAmount } } |
| 102 | + ) |
| 103 | + sessionCollection.updateOne( |
| 104 | + { "customer": fromAccount }, |
| 105 | + { $inc: { "balance": -1 * transferAmount } } |
| 106 | + ) |
| 107 | + |
| 108 | + } ) |
| 109 | + |
| 110 | +The lambda function includes initial checks to validate the operation |
| 111 | +before updating the ``balances`` collection. |
| 112 | + |
| 113 | +MongoDB automatically completes the transaction. |
| 114 | + |
| 115 | +- If both ``updateOne()`` operations succeed, |
| 116 | + ``Session.withTransaction()`` commits the transaction when the callback |
| 117 | + returns. |
| 118 | +- If an exception is thrown inside the callback, |
| 119 | + ``Session.withTransaction()`` ends the transaction and rolls back any |
| 120 | + uncommitted changes. |
| 121 | + |
| 122 | +.. note:: |
| 123 | + |
| 124 | + By default, MongoDB ends transactions that run for more than 60 |
| 125 | + seconds. If you want to extend the default timeout to experiment with |
| 126 | + transactions in :binary:`mongosh`, see :ref:`transaction-limit`. |
| 127 | + |
0 commit comments