3

I want to modify two schema while adding data. For that I used ACID transaction of mongodb with nodejs as follow. But, when I run program it displays the error like

(node:171072) UnhandledPromiseRejectionWarning: MongoError: Given transaction number 3 does not match any in-progress transactions. The active transaction number is 2 at MessageStream.messageHandler (/home/user/Projects/project/node_modules/mongodb/lib/cmap/connection.js:272:20) at MessageStream.emit (events.js:375:28) at MessageStream.emit (domain.js:470:12) 
addData = async(request: Request, response: Response) => { const session = await stockSchema.startSession() try { const userData = request.body let data = {} const transaction = await session.withTransaction(async() => { try { userData.products.map(async(item: any) => { await inventorySchema.findOneAndUpdate({ _id: item.materialID }, { $inc: {qty: -item.qty }}, { session }); }); data = new stockSchema(userData); await data.save({ session }); } catch (error) { await session.abortTransaction() throw new Error("Could not create data. Try again."); } }); if (transaction) { session.endSession() return returnData(response, data, 'Data created successfully.'); } else { throw new Error("Could not create data. Try again."); } } catch (error: any) { session.endSession(); return Error(response, error.message, {}); } } 
1
  • Does withTransaction now support being called with async like that? Commented Aug 26, 2021 at 0:15

1 Answer 1

3

So you might have figured out the answer to this already, but anyway, after months of frustration, and no clear answer on the internet, i finally figured it out.

The problem with your code above is that you are passing session into a database operation (the .findOneAndUpdate function above) that is running within .map . Meaning, your 'transaction session' is being used concurrently, which is what is causing the error. read this: https://www.mongodb.com/community/forums/t/concurrency-in-mongodb-transactions/14945 (it explains why concurrency with transactions creates a bit of a mess.)

Anyway, instead of .map, use a recursive function that fires each DB operation one after another rather than concurrently, and all your problems will be solved.

You could use a function something like this:

const executeInQueue = async ({ dataAry, //the array that you .map through callback, //the function that you fire inside .map idx = 0, results = [], }) => { if (idx === dataAry.length) return results; //else if idx !== dataAry.length let d = dataAry[idx]; try { let result = await callback(d, idx); results.push(result); return executeInQueue({ dataAry, callback, log, idx: idx + 1, results, }); } catch (err) { console.log({ err }); return results.push("error"); } }; 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.