Nodejs mongodb find and update multiple documents in transaction

1.4k Views Asked by At

I have a mongo 4.2 replica set. I have N processes running concurrently and trying to read a collection. This collection is like a queue. I'd like to read 100 elements and update them in a transaction so other processes won't try to read those.

My code goes:

const collection = client.db("test").collection(TEST_COLLECTION);

const session = client.startSession();

try {

    let data = null;

    await session.withTransaction(async () => {
        console.log("starting transaction")

        data = await collection.find({ runId: null }, { _id: 1, limit: 100 }).toArray();

        const idList = data.map(item => item._id.toHexString());

        await collection.updateMany(
            { runId: { $in: idList } },
            { $set: { runId: runId } },
            { session });

        console.log("Successful transaction")
    });

    data.map(item => {
        // process element one by one and update them (no need for transaction here)
    })

} catch (e) {
    console.error("The transaction was aborted due to an unexpected error: " + e);
} finally {
    await session.endSession();
    console.log("Closing transaction")
}

this is the code I've got right now. The thing is that find() won't accept options so I can't pass the session. This means it won't be part of the transaction.

the mongodb documentations states that: When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).

So I'm assuming that this is actually not transactional only the update part which not solves my problem. Is there any way to include both in my transaction? Any ideas on this? Other/better options?

Thanks

EDIT: So I was staring at my question for 15 minutes when it hit me. If I update first using the transaction. Then querying with the runId even outside of the transaction I can achieve my goal. Am I right? Is it so easy?

EDIT2: Edit1 was stupid now I can't limit to 100 items. Back to the start.

EDIT3: I'am using native mongodb nodejs driver.

1

There are 1 best solutions below

3
On BEST ANSWER

To use a find in a transaction, pass the session using the session method:

doc = await Customer.findOne({ name: 'Test' }).session(session);

See Transactions in Mongoose