I am working on MongoDB, which has a model as below:
const appJobSchema = new mongoose.Schema({
data: [
{ type: Schema.Types.Mixed }
],
stat: {
dataCount: { type: Number, default: 0 },
}
})
What I need to do is to update a few records in the array field, at the same time update the latest array length to the stat.dataCount
field.
export async function updateDataById(id: string, records: any[]) {
return await model.updateOne({ '_id': id }, {
'$addToSet': { 'data': { '$each': records } } ,
'$set': {
'stat.dataCount': { $size: "$data" }
}
});
}
But I got an error saying:
UncaughtException: Cast to Number failed for value "{ '$size': '$data' }" (type Object) at path "stat.dataCount"
Any idea how I would do it?
Update
First try on the pipeline:
return await model.updateOne({'_id':id},
[
{
"$set": {
"data": {
$concatArrays: [ "$data", records ]
}
}
},
{
'$set': {
'stat.dataCount': { $size: "$data" } }
}
]);
It is working, but the problem is that solely adding values to the data array would cause duplicate values, and that is why I have to use $addToSet
in order to remove the duplicates.
Second try on the pipeline:
Model.updateOne({'_id':id},
[
{ '$addToSet': { 'data': { '$each': records } }, '$inc':{ 'runCount': 1 } ,
{
'$set': {
'stat.dataCount': { $size: "$data" } }
}
]);
It throws out:
UncaughtException: Invalid update pipeline operator: "$addToSet".
Same for $inc
.
Finally get it working by $setUnion
with pipeline,
await Model.updateOne({'_id':id},
[
{
"$set": {
"data": {
$setUnion: [ "$data", records ]
}
}
},
{
'$set': {
'stat.dataCount': { $size: "$data" } }
},
]);
But what if I need to use $inc
? It still seems a problem.
As you are switching to the update pipeline to use the aggregation operator, the update operator is not supported. You need to switch to all aggregation operators, such as $sum
to replace the $inc
.
await Model.updateOne({'_id':id},
[
{
"$set": {
"data": {
$setUnion: [ "$data", records ]
},
"runCount": {
$sum: [ "$runCount", 1 ]
}
}
}
},
{
"$set": {
"stat.dataCount": { $size: "$data" }
}
},
]);