Home > Software engineering >  MongoDb push only if property not already in array
MongoDb push only if property not already in array

Time:10-17

I'm trying to update a nested array in a document only if the array does not already include the item like so:

await userCollection.findOneAndUpdate(
    { _id: ObjectId('616acc597ebda90ca6ffee21') },
    {
      'devices': {
        $push: {
          $cond: {
            if: {
              $in: [req.body.serial, '$devices']
            },
            then: '$devices',
            else: { serial: req.body.serial, data: [] }
          }
        }
      }
    },
    { returnOriginal: false },
    (err, _) => {
      if (err) {
        return res.status(400);
      } else {
        return res.status(200).json(user.value);
      }
    }
  );

This is my user object:

{
    "_id": "616acc597ebda90ca6ffee21",
    "username": "[email protected]",
    "displayName": "Test",
    "devices": [
      {
        "serial": "865674036421275",
        "data": [
          {
            "timestamp": "2021-10-16T12:36:35.799Z"
          },
          {            
            "timestamp": "2021-10-16T12:41:33.633Z"
          },
          {           
            "timestamp": "2021-10-16T12:52:03.055Z"
          }
        ]
      },
      
    ],
    "hashedPassword": "R5vt3vY7vEvTHvhC7YGNOWuIjBUQGLqsd92QGE06tjU=",
    "salt": "6RS0OVIFboCkIEPHdZmTcQ==",
    "dateCreated": "2021-10-16T12:58:00.294Z"
  }

How will I check if serial is already in devices? Also, is it possible to throw an error if it already exists?

CodePudding user response:

There's an update operator called addToSet check it here

CodePudding user response:

Query

  • find to update only documents that dont have this serial
  • replace the "000" with the serial you want to add
  • push in the end
  • updateOne will return the result, and you can see if update is done or not, see your driver method details.

*it will be fast, and you dont need an index on devices.serial because it selects a specific document already with the _id match

Test code here

db.collection.update({
  "_id": ObjectId("616acc597ebda90ca6ffee21"),
  "devices.serial": {
    "$ne": "000"
  }
},
{
  "$push": {
    "devices": {
      "serial": "000",
      "data": []
    }
  }
})

We cant mix update operators with aggregate operators. $cond is aggregate operator, it cant be mixed with $push update operator. (aggregate $push is for group, cant add to an array)

We can do the update with update pipeline, but here a normal update is simpler.

  • Related