For every operation my application does on MongoDB I want to have the old and new version of the document so I can emit an event with both version:
{
type: 'UPDATE',
before: documentBeforeUpdate,
after: documentAfterUpdate
}
The way I do this right now is to first issue a findOne
with the query, then do a findOneAndUpdate
with the update, but using the document's _id
for the query. So if the query is actually inducing load on the database I'm not paying that price twice:
async function updateOne(query, updates) {
const oldDocument = await this.model
.findOne(query, null, { lean: true })
.exec();
if (!oldDocument) {
return;
}
const newDocument = await this.model
.findOneAndUpdate({ _id: oldDocument._id }, updates, {
new: true,
lean: true
})
.exec();
// document vanished before it could be updated
if (!newDocument) {
return;
}
await this.emit("UPDATE", {
before: oldDocument,
after: newDocument,
type: "UPDATE"
});
return newDocument;
}
I have similar functions for updateMany
, delete{One,Many}
, createOne
etc.
Now my question is if there is a more performant way than doing that?
Context
What I want to do is to decouple code that would denormalize data in the database for query-performance reasons. Assuming I have an application where you can reserve tables in a restaurant, then I want the reservations to be in there own collection, but I also want to have the availability-information for each table cached in the table's own document. So I can query the table's collection for tables available at a specific time.
// reservation
{
_id: ObjectId,
table: ObjectId,
from: Date,
to: Date
}
// table
{
_id: ObjectId,
reservations: [
{ _id: ObjectId, from: Date, to: Date },
// ...
]
}
When having an event system where I can listen for creates, updates and deletes of documents, I don't need to call the code that is updating the table's reservation property directly from the code that is updating the reservation document. This is the architecture I want to achieve.