I\'d like to have a single method that either creates or updates a document for a policy. Searching and trying different techniques like this one, I have come up with a nul
Thanks to JohnnyHK for a helpful answer above. I came up with a one-liner since it's used so frequently:
query = args._id ? { _id: args._id } : { _id: new ObjectId() };
It relies on the following require:
const ObjectId = require('mongodb').ObjectID;
Since we can now add default properties while destructuring objects in JavaScript, in the case that we are checking to see if a document exists, I find this the easiest way to either query via an existing _id or create a new one in the same operation, avoiding the null id problem:
// someController.js using a POST route
async function someController(req, res) {
try {
const {
// the default property will only be used if the _id doesn't exist
_id: new mongoose.Types.ObjectId(),
otherProp,
anotherProp
} = req.body;
const createdOrUpdatedDoc = await SomeModel.findOneAndUpdate(
{
_id
},
{
otherProp,
anotherProp
},
{
new: true,
upsert: true
}
).exec();
return res.json(201).json(createdOrUpdatedDoc);
} catch (error) {
return res.json(400).send({
error,
message: "Could not do this"
})
}
}
I had this same problem and couldn't figure out a way to get it to work. I ended up writing my own upsert method like so....
var upsert = function(model, data, f){
if (!data._id) {
model.create(data, f);
} else {
var id = data._id;
delete data._id;
model.findOneAndUpdate({_id: id}, data, f);
}
}
That allows me to call it for any of my models with one line of code...
upsert(Team, team, f);
There might be a better way to do it, but this is working for me. I can do updates and inserts and I don't get a null _id on insert.
null
is a valid _id
value in MongoDB, so if you don't want it used in new docs you must ensure that a null
value is replaced with a new ObjectID
in query
:
var query = {_id: plcy._id};
if (!query._id) {
query._id = new mongoose.mongo.ObjectID();
}
// the rest stays the same...
I am not using Mongoose, but I run into similar issue with MongoDB. For Upsert action when new object was inserted the MongoDB was setting null
to _id
.
I was calling:
findOneAndUpdate({my_id:'my_unique_id'}, obj, {upsert: true})
where obj._id
was undefined
.
The problem was that _id
was present on list of keys Object.keys(obj)
. I found that I was assigning obj._id = some_variable
, where some_variable
was undefined
, and that was causing _id
to appear on a list of keys.
I applied workaround by calling right before upsert:
if (_.isUndefined(obj._id)) {
delete obj._id;
}
Try setting 'new' parameter to true:
{ upsert: true, new: true }
More info: https://github.com/Automattic/mongoose/issues/2939