How to use $cond in updateOne using mongoose?

Viewed 638

I want to update a value in the mongodb depending on its previous value, if null (saved as string) then I will update it to a new value, otherwise I want to keep it as it is.
Here is my code:

User.updateOne({_id: user._id}, {$set: {
                        deviceId: {$cond: [{$eq: ['null']}, req.body.deviceId, 'null']}
                    }}, null, function (err, res){
                    if (err){
                        return done(err)
                    }else{
                        return done(null, user)
                    }
                })

But I get the following error (I believe it indicates that my syntax is not correct):

CastError: Cast to string failed for value "{ '$cond': [ { '$eq': [Array] }, 'MYDEVICEID', 'null' ] }" (type Object) at path "deviceId"
    at model.Query.exec (D:\X_APP\XAPP_BACKEND\node_modules\mongoose\lib\query.js:4478:21)
    at _update (D:\X_APP\XAPP_BACKEND\node_modules\mongoose\lib\query.js:4330:11)
    at model.Query.Query.updateOne (D:\X_APP\XAPP_BACKEND\node_modules\mongoose\lib\query.js:4229:10)
    at _update (D:\X_APP\XAPP_BACKEND\node_modules\mongoose\lib\model.js:3834:16)
    at Function.updateOne (D:\X_APP\XAPP_BACKEND\node_modules\mongoose\lib\model.js:3770:10)
    at file:///D:/X_APP/XAPP_BACKEND/middlewares/userMiddleware.js:24:32
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

I searched and saw many applications using the Aggregation but is it possible to achieve it using my approach updateOne in mongoose? if yes, what is the issue with my application?

2 Answers

The $cond is an aggregation operator you can not use in a simple update query,

if null (saved as string) then I will update it to a new value, otherwise I want to keep it as it is.

If you are trying to update a single field, i would suggest a simple approach,

You can check the condition in the query part if deviceId is null then update new deviceId otherwise it will ignore update operation,

await User.updateOne(
  { 
    _id: user._id,
    deviceId: "null"
  }, 
  {
    $set: {
      deviceId: req.body.deviceId
    }
  }, 
  null, 
  function (err, res){
    if (err){
      return done(err)
    }else{
      return done(null, user)
    }
  }
);

Second, as per your try, you can achieve by update with aggregation pipeline starting from MongoDB 4.2,

await User.updateOne(
  { _id: user._id }, 
  [{
    $set: {
      deviceId: {
        $cond: [
          { $eq: ["$deviceId", "null"] },
          req.body.deviceId,
          "null" // or you can use "$deviceId"
        ]
      }
    }
  }], 
  null, 
  function (err, res){
    if (err){
      return done(err)
    }else{
      return done(null, user)
    }
  }
)

No, you can't use $cond with the update, MongoDB doesn't allow this.

But you still can achieve this by using this way: MongoDB update with condition

Related