2

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.

2
  • 1
    mongoplayground.net/p/uvLO3drlZ9q Commented Feb 3 at 15:33
  • MongoDB $inc is the update operator, since you change it to pipeline, you should revamp to $set and $sum to increment the value: { $set: { 'runCount': { $sum: [ '$runCount', 1] } } } Commented Feb 4 at 1:09

1 Answer 1

2

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" }  
    }
  },
]);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.