Mongoose withTransaction only partially executes

Viewed 685

Mongoose's session.withTransaction helper is only executing the first write. Here's the code:

const session = await mongoose.startSession();

await session.withTransaction(async () => {
  const member = await Member.create([{
    name: 'John Doe'
    email: 'johndoe@example.com',
  }], { session });

  await User.updateOne({ _id: req.user.id }, { member: member._id }, { session });
});

This code creates a new Member in the database, but does not update the User. Isn't the point of a transaction that it only goes through if every operation succeeds? What am I doing wrong; or is this just not possible with Mongoose?

Mongoose: 5.9.26, Node.js: 14.9.0

4 Answers

Check if starting the session with the model you are going to base the transaction on helps:

const session = await Member.startSession();

The error comes from https://github.com/mongodb/mongo/blob/11c68393df88a6f1ea4855e6ac15e54ca9f9d976/src/mongo/db/transaction_participant.cpp#L1712

// Cannot change committed transaction but allow retrying commitTransaction command.
uassert(ErrorCodes::TransactionCommitted,
        str::stream() << "Transaction " << requestTxnNumber << " has been committed.",
        cmdName == "commitTransaction" || !o().txnState.isCommitted());

Apparently you are trying to commit a transaction twice. Ensure you don't reuse it. Always end the session:

const session = await mongoose.startSession();

try { 
    await session.withTransaction(async () => {...})
} finally {
    await session.endSession()
}

Did you try to write it like this

{session :session }

Make sure you have replica setup, transactions requires replica to work.

Related