Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
26.92k stars 3.84k forks source link

mogoose transaction is not working with MongoDB #10994

Closed ats1999 closed 2 years ago

ats1999 commented 2 years ago

Code

router.get("/", async (req, res) => {
  const sesion = await mongoose.startSession();

  try {
    sesion.startTransaction();
    const blog = new Blog({ title: "blog title" });
    const byte = new Dsabytes({ topStory: "Not an ObjectId" });
    await blog.save();
    await byte.save(); // throw an error, because topStory should be an ObjectId

    await sesion.commitTransaction();
    sesion.endSession();
    res.send("OK");
  } catch (e) {
    console.log(e);
    await sesion.abortTransaction();
    sesion.endSession();
    res.status(500).send(e.toString());
  }
});

In the Dsabytes schema,I have defined topStory to be an ObjectId. When I run the above code with topStory:"6167213f5003f3d062dd833f" then it's working fine.

But, when await byte.save() throws an error then ideally sesion.abortTransaction() should remove the update caused by blog.save().

Database before API call

Blogs

[]

Dsabytes

[]

DB after API call

Blogs

[
{
  title:"blog title"
}
]

Dsabytes

[]

So, when it throws an error then both collections should be empty at the end?

vkarpov15 commented 2 years ago

You aren't actually using the session. Do:

    sesion.startTransaction();
    const blog = new Blog({ title: "blog title" });
    const byte = new Dsabytes({ topStory: "Not an ObjectId" });
    await blog.save({ session: sesion });
    await byte.save({ session: sesion }); // throw an error, because topStory should be an ObjectId

    await sesion.commitTransaction();
    sesion.endSession();
ats1999 commented 2 years ago

Gettig

MongoServerError: Transaction numbers are only allowed on a replica set member or mongos

vkarpov15 commented 2 years ago

@ats1999 the MongoDB server doesn't support transactions on standalone mongod instances. You need to run a replica set. Try using Atlas or run-rs