javascriptnode.jsmongodbexpressmongoose

MongoError: No transaction started


I am using Mongoose transactions for the first time. Following the documentation and some articles, I was able to get it running using run-rs for local replicas. However, I encountered two issues:

  1. Even though the transaction reflects on the replica sets, Mongoose always throws the error MongoError: No transaction started. I have tried checking for solutions but can't find any to solve this problem.
  2. Upon successful completion of the transaction, there's another async function that is meant to send notification emails. However, I realized that somehow, this notification email function runs before the transaction occurs, then the transaction function runs second. I am guessing this might have to do with promises, correct me if I am wrong.

Here's what the two functions look like:

await transactionDb
       .handleMoneyTransfer({
            senderId,
            receiverId: paymentInfo.getReceiver(),
            amount: paymentInfo.getAmountToPay(),
            ref
          })
return await sendNotificationEmail({ ref, user })

The handleMoneyTransfer function is meant to run first, then the sendNotificationEmail is meant to run next, but that's not the case here.

Here is the code that handles the Mongoose transaction listed below.

async function handleMoneyTransfer({ senderId, receiverId, amount, ref }) {
    const session = await mongoose.startSession()
    try {
      const sender = await User.findOne({ _id: senderId }).session(session)
      sender.balance -= amount
      await sender.save({ session })
      const receiver = await User.findOne({ _id: receiverId }).session(session)
      // receiver.balance += amount
      const transactionInfo = await Transaction.findOne({
        reference: ref
      }).session(session)
      const newEscrow = await new Escrow({
        amount,
        reference: ref,
        buyerInfo: {
          buyerId: sender._id,
          email: sender.email
        },
        sellerInfo: {
          sellerId: receiverId,
          email: receiver.email
        },
        currentTransaction: {
          transaction: transactionInfo
        }
      })
      await newEscrow.save({ session })
      await session.commitTransaction()
    } catch (error) {
      await session.abortTransaction()
    } finally {
      session.endSession()
    }
  }

Here is how I connect using Mongoose:

const setupDB = async (uri, dbUrl) => {
  try {
    await mongoose.connect(`${uri}/${dbUrl}`, {
      useUnifiedTopology: true,
      useNewUrlParser: true,
      replicaSet: 'rs'
    })
    console.log('Connected')
  } catch (e) {
    return console.log(e)
  }
}

which is translated to this:

setupDB(
  'mongodb://DESKTOP-SNA1HQK:27017,DESKTOP-SNA1HQK:27018,DESKTOP-SNA1HQK:27019',
  'escrow?replicaSet=rs'
)

Now, I am stuck on fixing the No transaction started error and also getting these functions to run in the order they are placed.

Help will be very much appreciated, thank you in advance.


Solution

  • You seem to be missing the actual start of a transaction. Adding the following to your code should fix the issue:

    async function handleMoneyTransfer({ senderId, receiverId, amount, ref }) {
        const session = await mongoose.startSession()
        session.startTransaction();
        // rest of your code
    
    }