I want to trigger a function each time an element is inserted/created in a collection, not when it's updated. (And I need the ID of the element created)
Here's what I did:
schema.pre("save", function() {
this.$locals.wasNew = this.isNew;
});
schema.post("save", function() {
if (this.$locals.wasNew) {
console.log(`User ${this.id} created!`);
}
});
It works with calls like this one:
await UserModel.create({
mail
});
But not with calls like this one:
const user = await UserModel.findOneAndUpdate(
{ mail },
{ $set: { mail } },
{ new: true, upsert: true }
);
It seems like upsert
does not trigger the save
hook with the isNew
boolean set to true.
Am I doing it wrong? Missing something? Or is there an alternative way of doing it?
It is not possible to have the same code in document.save hooks executed on the query.findOneAndUpdate as well. The reason is that the hooks in document.save will not be executed for query methods. For more, please see link 1 below.
However, there are following workarounds:
Use the two separate methods findById and save, the reasoning is that findOneAndUpdate is effectively doing the same. You may be able to see the original discussion on these lines here, reference link 2.
Using change streams, reference link 3.
As @joe has commented, using includeResultMetadata, reference link 4.
Please also see the sample code below for the options 2 and 3.
const mongoose = require('/mongoose');
const { Schema } = mongoose;
run().catch((error) => console.log(error));
async function run() {
await mongoose.connect('mongodb://127.0.0.1:27108', { replicaSet: 'rs' });
const SomeModel = mongoose.model('Somemodel', new Schema({ key1: String }));
await SomeModel.deleteMany();
SomeModel.watch().on('change', (data) => {
if (data.operationType == 'insert') {
console.log(`change stream, new document, _id: ${data.fullDocument._id}`);
}
});
await new SomeModel({ key1: 'key1 value 1' }).save();
const doc2 = await SomeModel.findOneAndUpdate(
{ key1: 'xyz' },
{ key1: 'key1 value2' },
{ new: true, upsert: true, includeResultMetadata: true }
);
!doc2.lastErrorObject.updatedExisting &&
console.log(`ResultMetadata, new document, _id: ${doc2.value._id}`);
}
OUTPUT:
change stream, new document, _id: 6643275fdb709107184e999a
ResultMetadata, new document, _id: 6643275f7550f5d65e7ba6a3
change stream, new document, _id: 6643275f7550f5d65e7ba6a3
Links