I setup a mongoose schema like so:
const expertSchema = new mongoose.Schema({ firstName: { type: String, required: true, }, lastName: { type: String, required: true, }, contactMethods: { type: [ContactMethod.schema], } }) expertSchema.plugin(autoIncrement.plugin, { model: 'EXP-', startAt: 1, prefix: 'EXP-' }); const Expert = mongoose.model('Expert', expertSchema); const contactMethodsSchema = new mongoose.Schema({ type: { type: String, required: true, }, value: { type: String, required: true, }, preferred: { type: Boolean } }); contactMethodsSchema.plugin(autoIncrement.plugin, { model: 'CON-', startAt: 1, prefix: 'CON-' }); const ContactMethod = mongoose.model('ContactMethod', contactMethodsSchema)
I'm using the mongoose-auto-increment plugin to auto-increment my monogodb document's id's (actually using this fork, but they are basically the same)
I have some code that seeds my dev. db on restart which looks like this:
const contMethod1 = new models.ContactMethod({ type: 'email', value: "janedoe@acme.org", preferred: false, }); const contMethod2 = new models.ContactMethod({ type: 'phone', value: "+12125550711", preferred: true, }); const expert1 = new models.Expert({ firstName: 'Jane', lastName: 'Doe', contactMethods: [contMethod1, contMethod2] }); expert1.save();
This code works great and I end up with a document that looks like:
{ "_id": "EXP-1", "firstName": "Jane", "lastName": "Doe", "contactMethods": [{ "type": "email", "value": "janedoe@acme.org", "preferred": false, "_id": "CON-1" }, { "type": "phone", "value": "+12125550711", "preferred": true, "_id": "CON-2" } ] }
However when my frontend posts this edited data back to me I get json that looks like:
{ _id: "EXP-1", "contactMethods": [{ "type": "email", "value": "janedoe@acme.org", "preferred": false, "_id": "CON-1" }, { "type": "phone", "value": "+12125550711", "preferred": true, "_id": "CON-2" }, { "type": "whatsapp", "value": "+123456789", "preferred": false } ] }
Now what I want is to update existing embedded documents and/or add new ones if needed. I setup this code for this purpose (I appreciate there is probably a much more intelligent way to implement this, but even so, it sort of "works"):
req.body.contactMethods.map((_, index) => { if (_._id) { expert = req.context.models.Expert.findOneAndUpdate({ "contactMethods._id": _._id }, { $set: { "contactMethods.$.type": _.type, "contactMethods.$.value": _.value, "contactMethods.$.preferred": _.preferred } }, { useFindAndModify: false, returnOriginal: false, runValidators: true }) } else { expert = req.context.models.Expert.findOneAndUpdate({ "_id": req.user._id, }, { $push: { "contactMethods": _ } }, { useFindAndModify: false, returnOriginal: false, runValidators: true }) } })
Unfortunately, is this scenario my plugin doesn't "trigger" or invoke and I end up with a document updated in the collection which lacks a "_id" property for the newly pushed contactMethod.
Why is my plugin not being called on the findOneAndUpdate call?
I found this question but my plugin doesn't use ES6 syntax. Also I found this comment but the current mongoose documentation doesn't state that anymore so I was kinda hoping maybe they changed/fixed it.
Thanks, (first question. phew..)
I eventually solved (or rather worked around this) by changing my code and splitting up the addition of a new contact method to two operations: findOne and save, like so:
req.body.contactMethods.map((_, index) => {
if (_._id) {
expert = req.context.models.Expert.findOneAndUpdate({
"contactMethods._id": _._id
}, {
$set: {
"contactMethods.$.type": _.type,
"contactMethods.$.value": _.value,
"contactMethods.$.preferred": _.preferred
}
}, {
useFindAndModify: false,
returnOriginal: false,
runValidators: true
})
} else {
expert = req.context.models.Expert.findOne({
"_id": req.user._id,
})
expert.contactMethods.push(_);
expert.save({ validateModifiedOnly: true });
}
})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.