3

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?

turivishal
  • 34,368
  • 7
  • 36
  • 59
Jagar
  • 777
  • 9
  • 24

3 Answers3

5

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)
    }
  }
)
turivishal
  • 34,368
  • 7
  • 36
  • 59
3

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

  • 1
    I just saw that `collection.update()` is deprecated in mongoose, so is there another way to achieve it? – Jagar Jul 05 '21 at 10:10
0

Use CollectionName.findByIdAndUpdate() it's works for me.

router.post('/:id', auth, async (req, res) => {
  
  try {
    /*  Try this approach  */
    const myNewData = req.body;
    await MyCollectionName.findByIdAndUpdate( myNewData._id , {
      email: req.body.email,
      password: req.body.password,
      etc: req.body.etc
    },
    {new: true} 

  } catch (err) {
    res.status(400).json({ message: err.message })
  }

})

Note: set the option new to true to get the new version of the doc

GMKHussain
  • 3,342
  • 1
  • 21
  • 19