Search code examples
node.jsmongodbtransactionsupdatesdocument

Mongodb updates within a transaction


I am trying to update a document from within a transaction. I am using 'findbyidandupdate' with a session object passed in, but I get this error:

MongooseError: Callback must be a function, got [object Object]

Related backend code in Node.js. The session object is created from a data model object, in this case the data object is 'Device':

const session = await Device.startSession();

const transactionOptions = {
        readPreference: 'primary',
        readConcern: { level: 'local' },
        writeConcern: { w: 'majority' }
    };

const transactionResults = await session.withTransaction( async () => {
               const deviceUpdateResults = await 
    Device.findByIdAndUpdate(
                {session},
                (deviceid),
                {$push: {"reviews": (reviewid)}},
                { new : true, safe: true})
}

Looks like the method cannot accept a session object. How do I pass a session object to an update method?


Solution

  • From the Mongoose documentation, findByIdAndUpdate has a different signature from the one you have used. First of all, findByIdAndUpdate is just an utility method that eventually calls findOneAndUpdate, as also pointed out in the documentation, so the arguments are basically the same.

    The problem you have is that you are passing too many arguments: since you are using the async version of the function, you should pass at most 3 arguments. Instead, for the callback version, you need 4 arguments with the callback at the end.

    This is how you should have called the findByIdAndUpdate:

    const deviceUpdateResults = await Device.findByIdAndUpdate(
        deviceid,
        { $push: { "reviews": reviewid } },
        { session: session, new: true}
    );
    

    Few observations not really about your issue:

    • I have always used the NodeJS native driver for MongoDB, so Mongoose is pretty unknown to me, but if you start a ClientSession with startSession, I expect you also need to close it with endSession. The alternative (for the native driver) is to use withSession that accepts a callback where the session is valid.
    • As for now, readPreference: 'primary' can be omitted because the transaction can only happen in the primary. The default readConcern is local, so you could omit that too.
    • Isn't safe option deprecated? It is not even listed in the documentation anymore.