How to atomically update one array item's property=true and all other array items' property=false

I have documents with an array field that contains nested documents (objects). On the nested objects, there is a field called “default” in which only one array item can have default=true. If another nested document had default=true, I want to mark it with default=false or remove the “default” field completely AT THE SAME MOMENT I update the desired nested document with default=true.

Example document:

{
  id: "docId",
  colors: [
    {value: "red", default: true},
    {value: "white"},
    {value: "blue"}
  ]
}

How can I update the document so that “white” is the only nested document with “default=true” and other nested documents have either no default property or “default=false” ?

Pseudocode:

magicUpdate("docId", "white", true)  // only white should have default=true
magicUpdate("docId", "blue", true)  // only blue should have default=true

I think I’m going to change my data model to avoid the problem. Luckily I have the luxury to change it. A more convenient data model will look like:

{
  id: "docId",
  colorsDefault: "red",
  colors: [
    {value: "red"},
    {value: "white"},
    {value: "blue"}
  ]
}

Now the update command is obvious. I just need to change a single field and no array elements.

{
  $set: {colorsDefault: "blue"}
}

Still, I wonder if it is possible to remove the property default=true from one array element while atomically updating another element.

I prefer the schema

For completeness, to

you use arrayFilters. In your case the following should work:

c.updateOne( { id : "docId" } ,
    { $unset : { "colors.$[oldDefault].default" : 1 } ,
      $set : { "colors.$[newDefault].default" : true }
    } ,
    { arrayFilters :
      [ { "oldDefault.default" : true } ,
        { "newDefault.value" : "blue"}
      ]
    } )
1 Like

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