Transaction failed but earlier statement hold true

Below code snippet on sample_anlytic db

const session = db.getMongo().startSession()
session.startTransaction()
const account = session.getDatabase('sample_analytics').getCollection('accounts')
const customer = session.getDatabase('sample_analytics').getCollection('customers')
account.insertOne({
  account_id: 00009,
  limit: 88888
})
account.updateOne( { account_id:00009 }, {$inc: { limit: -100.00 }})
**customer.insertyOne({ name:"vinci5"})**

session.commitTransaction()

I purpously written wrong statement higlighted but after commit i query
db.accounts.find({account_id:9})
i got limit: 88788

Hey @VIKASH_RANJAN1,

Welcome to the MongoDB Community Forums! :leaves:

Can you please share the full code, along with the error message and result of the query you are running? I tried the code on my end with the python driver and everything works as one expects in case of a transaction, ie. when an error occurred in between the transaction, the customers collection did not have any document account_id: 9. This is the code I ran in pymongo and everything worked as expected, maybe you can try this in your environment:

uri = <your_string_here>
client = pymongo.MongoClient(uri)
db = client.sample_analytics
account = db.accounts
customer = db.customers
with client.start_session() as session:
    with session.start_transaction():
        account.insert_one({'account_id': 9,'limit': 88888 }, session=session)
        account.update_one( { 'account_id':9 }, {'$inc': { 'limit': -100.00 }},session=session)
        customer.inserty_one({'name':"vincy5"},session=session) //change to insert_one to make the transaction work

Regards,
Satyam


Please find screenshot .It ignore syntax error and commit transaction

It looks like you are missing a parameter to do your updateOne inside the transaction.

See https://www.mongodb.com/docs/manual/core/transactions/#std-label-transactions-write-concern to see how to do updateOne withing a transaction.

I am simulating if txn failed in between the session it should rollback but it still hold true for syntax error(insertyOne). though for logical error it behaves differently

Hi @VIKASH_RANJAN1

What @Satyam and @steevej alluded to is that your updateOne() statement is performed outside of the transaction. This is why it appears to do the wrong thing.

In the first example, you need to add the { session } variable into the updateOne() as seen in this Node driver transaction example to signify that this statement is part of the session and thus the transaction.

In the second example, the updateOne() statement contains an error and thus it was not executed. Transaction or not, it makes no difference in this case.

Try to modify your updateOne() to be like account.updateOne( { account_id:00009 }, {$inc: { limit: -100.00 }}, { session }) and it should behave as expected.

Hope this clears things up.

Best regards
Kevin

2 Likes

It’s inside session via below command
const session = db.getMongo().startSession()
session.startTransaction()
const account = session.getDatabase(‘sample_analytics’).getCollection(‘account’)
const customer = session.getDatabase(‘sample_analytics’).getCollection(‘customer’)


session.commitTransaction()

It is not. Unlike most SQL-style interactive session, a statement starting a session does not mean that all the subsequent statements are inside that session. In MongoDB, you’ll need to include the session object in the CRUD statement.

As I have mentioned in my earlier reply, you need to modify your updateOne statement to include the session object:

I encourage you to read through the link I posted earlier, which explains in detail how sessions and transactions work in MongoDB: https://www.mongodb.com/docs/drivers/node/current/fundamentals/transactions/#core-api-implementation since transaction CRUD syntax in MongoDB is a bit different from what SQL does. The concept of the transaction itself are identical, though

Best regards
Kevin

Hi Kelvin,
Sorry for bothering again then why did my scenario2 where I written same way aborted and rollbacked to original value

Ah I see where the confusion is :slight_smile:

I apologize to exacerbate the confused situation. I was using the example of a Node program (where {session} is required to make the CRUD operation work inside the transaction), and you’re using mongosh and grabbed the database from the Session object as per https://www.mongodb.com/docs/manual/reference/method/Session/#mongodb-method-Session

In scenario 1, I think everything behaved like they should:

  1. start transaction
  2. subtract 100 from account 9
  3. commit transaction
  4. account 9 has limit subtracted by 100 as it should

In scenario 2, there’s a MongoServerError:

  1. start transaction
  2. subtract 100 from account 9
  3. intentionally induce a MongoServerError
  4. transaction aborted
  5. account 9 was not subtracted

Am I following your thought so far correctly?

Basically scenario 2 showed that a MongoServerError would automatically abort a transaction. This is in contrast with your earlier example where you called insertyOne: it resulted in TypeError instead of MongoServerError, so the transaction didn’t auto abort.

Is this the information you’re looking for? Sorry again for the confusion.

Best regards
Kevin

So we can conclude that
Scenario 1: MongoDB Perspective its valid since Account :0 don’t exists. But taking a case financial matter were Debit=Credit will fail the business validation. Hence Application has to be intelligent enough to catch modiifiedCount:0 and do a rollback instead of commit.

MongoDB only rollback MongoServerError not TypeError .There also application need to be intellegent enough to do rollback instead of commit

In my opinion, MongoDB can only rollback what it can detect. The database is not aware of what else you are doing in your code.

A TypeError is a bug in your code.

Yes, your application should be catching all the errors that may happen in your code and ask for a rollback.