Search code examples
mongodbmongoose

update mongodb 's array with $addToSet and set array's length with { '$size': '$array' } not working


I am working on mongodb which has model like the 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 to the mongodb array field - data, 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 would I 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 solely adding values to data array would cause the duplicate values, and that is why I have to use $addToSet in order to remove the duplicate.

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 seems still a problem.


Solution

  • 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" }  
        }
      },
    ]);