How to toggle a boolean field in an array using $set and positional operator

I have documents in my collection in the format

  {
    "_id": "61a02dc3e044cc34ce8a3a2f",
    "name": "Product 1",
    "status": true,
    "items": [
      {
        "_id": "61a02dc3e044cc34ce8a3a30",
        "foodName": "Item 1",
        "price": 10,
        "status": true
      },
      {
        "_id": "61a02dc3e044cc34ce8a3a31",
        "foodName": "Item 2",
        "price": 20,
        "status": false
      }
    ]
  }

Now lets say I want to toggle the status of where items._id : 61a02dc3e044cc34ce8a3a31. I tried with the positional operator but it simply doesn’t give me the result

This is the query I tried

db.collection.update({
  _id: "61a02dc3e044cc34ce8a3a2f",
  "items._id": "61a02dc3e044cc34ce8a3a31"
},
{
  $set: {
    "items.$.status": {
      $not: [
        {
          $eq: [
            "$items.$.status",
            true
          ]
        }
      ]
    }
  }
})

I get back the below which is not what I want

  {
    "_id": "61a02dc3e044cc34ce8a3a2f",
    "items": [
      {
        "_id": "61a02dc3e044cc34ce8a3a30",
        "foodName": "Item 1",
        "price": 10,
        "status": true
      },
      {
        "_id": "61a02dc3e044cc34ce8a3a31",
        "foodName": "Item 2",
        "price": 20,
        "status": {
          "$not": [
            {
              "$eq": [
                "$items.$.status",
                true
              ]
            }
          ]
        }
      }
    ],
    "name": "Product 1",
    "status": true
  }

I mean it doesn’t read the conditions just assigns the condition object as the value. Here is the mongo playground link I tested with

Is this not possible. Any alternatives?

You need the following:

db.demo.bulkWrite([
{
updateOne: {
filter: { items: { $elemMatch: { _id: “61a02dc3e044cc34ce8a3a31” } } },
update: { $set: { “items.$.status”: true } }
}
}
])

Not quite a working solution as the problem is toggle a boolean field. What you share sets it to true even when it is already true. When true it has to be set to false.

hi thanks for the reply
but how do i access the positional operator in an aggregation pipeline. I’m not quite sure how to do it

Sorry for the delay. I don’t know.

I am pretty sure that you can achieve the toggle with $map along the lines:

{ $set : {
  "items" : { $map : {
    "input" : "$items" ,
    "as" : "item" ,
    "in" : { "$cond" : {
      "if" : { "$eq" : [ "$$item._id" , "61a02dc3e044cc34ce8a3a31" ] } ,
      "then" : {  "$mergeObjects : [
        "$$item" ,
        { "status" : { "$not" : [ "$$item.status" ] } }
      ] } ,
      "else" : "$$item"
    } }
  } }
} }
1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.