Update only single fields of all elements using all positional operator

Hi,
I maybe confused about how to use this positional operator so please help me.

I have this data:

[
  {
    "resource_id": "Machine-1",
    "resource_descr": "Machine Number 1",
    "components": [
      {
        "component_id": "mach-deas97u",
        "component_type": "Housing",
        "component_descr": "Housing 1"
      },
      {
        "component_id": "mach-7b83ta0",
        "component_type": "Base",
        "component_descr": "Base 1"
      },
      {
        "component_id": "mach-d1mxmd2",
        "component_type": "Peripherals",
        "component_descr": "Peripherals 1"
      }
    ]
  }
]

I only wanted to change the values of the component_descr of each of my array values coming from my web application.

I am expecting an output similar to this one:

  {
    "resource_id": "Machine-1",
    "resource_descr": "Machine Number 1",
    "components": [
      {
        "component_id": "mach-deas97u",
        "component_type": "Housing",
        "component_descr": "Housing 2"
      },
      {
        "component_id": "mach-7b83ta0",
        "component_type": "Base",
        "component_descr": "Base 2"
      },
      {
        "component_id": "mach-d1mxmd2",
        "component_type": "Peripherals",
        "component_descr": "Peripherals 2"
      }
    ]
  }

Note that the “component_descr” could be different for each object.

I was looking at the $[] operator but I am having trouble coming up with the solution.

I tried using this playground MongoDB Playground but it is not what I expected.

Can somebody please point me to the correct process? Thanks.

Hello @Nel_Neliel,

It is not possible with positional all $[] operator, but possible with array filters,

Your query would be something like this,

  • Use arrayFilters in the options of the query, check conditions and specify variables as i specified c1, c2, c3
  • pass the variables in the positional operator $[identifier] and specify the update value of the property
db.collection.update({
  "resource_id": "Machine-1"
},
{
  "$set": {
    "components.$[c1].component_descr": "Housing 2",
    "components.$[c2].component_descr": "Base 2",
    "components.$[c3].component_descr": "Peripherals 2"
  }
},
{
  arrayFilters: [
    { "c1.component_id": "mach-deas97u" },
    { "c2.component_id": "mach-7b83ta0" },
    { "c3.component_id": "mach-d1mxmd2" }
  ]
})

Playground

1 Like

Hi,
So this is how it should be. Thanks for pointing me in the right direction.

I do have an additional question though, what if I have multiple array records like a maximum of 30 then my query would be big I suppose? Is there an alternative in that case?

I don’t want to put these values in a separate collection as I think they are queried together with my parent object. Updating them in this manner might be a bit cumbersome. I wanted to know if there is an alternative as my readings about MongoDB is not that broad yet. Thank you.

Hello @Nel_Neliel,

Yes, the query would be big and might be expensive, This is because it has to iterate over the entire array to find the elements that match the filter criteria if your document has a huge array elements.
You need to check the server’s memory configuration as well if the query is slow.

You can test yourself here is the query: Playground

I don’t think of any other option, if this query is expensive divide it into 2/3 queries as per performance.

Wow, thank you very much for being helpful!
I will try to think of refactoring my schema design as this would be a performance problem but your help is greatly appreciated.

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