I'm trying to update a nested array in a document only if the array does not already include the item like so:
await userCollection.findOneAndUpdate(
{ _id: ObjectId('616acc597ebda90ca6ffee21') },
{
'devices': {
$push: {
$cond: {
if: {
$in: [req.body.serial, '$devices']
},
then: '$devices',
else: { serial: req.body.serial, data: [] }
}
}
}
},
{ returnOriginal: false },
(err, _) => {
if (err) {
return res.status(400);
} else {
return res.status(200).json(user.value);
}
}
);
This is my user object:
{
"_id": "616acc597ebda90ca6ffee21",
"username": "[email protected]",
"displayName": "Test",
"devices": [
{
"serial": "865674036421275",
"data": [
{
"timestamp": "2021-10-16T12:36:35.799Z"
},
{
"timestamp": "2021-10-16T12:41:33.633Z"
},
{
"timestamp": "2021-10-16T12:52:03.055Z"
}
]
},
],
"hashedPassword": "R5vt3vY7vEvTHvhC7YGNOWuIjBUQGLqsd92QGE06tjU=",
"salt": "6RS0OVIFboCkIEPHdZmTcQ==",
"dateCreated": "2021-10-16T12:58:00.294Z"
}
How will I check if serial is already in devices? Also, is it possible to throw an error if it already exists?
CodePudding user response:
There's an update operator called addToSet
check it here
CodePudding user response:
Query
- find to update only documents that dont have this serial
- replace the
"000"
with the serial you want to add - push in the end
- updateOne will return the result, and you can see if update is done or not, see your driver method details.
*it will be fast, and you dont need an index on devices.serial
because it selects a specific document already with the _id
match
db.collection.update({
"_id": ObjectId("616acc597ebda90ca6ffee21"),
"devices.serial": {
"$ne": "000"
}
},
{
"$push": {
"devices": {
"serial": "000",
"data": []
}
}
})
We cant mix update operators with aggregate operators.
$cond
is aggregate operator, it cant be mixed with $push
update operator. (aggregate $push
is for group, cant add to an array)
We can do the update with update pipeline, but here a normal update is simpler.