1

I was wondering if it was possible to update the embedded embedded value of an attribute (with two deep levels) please?

For example, if I have the following document :

{
    _id: ObjectId("5372523e4f611ef8255c5735"),

    places: [
        {
            idPlace: 2,
            namePlace: "Name of the place 2",
            typePlace: "Type of the place 2"
            },
            screens: [
                {
                    idScreen: 1,
                    nameScreen: "Name 1 of the screen",
                    statusScreen: false
                },
                {
                    idScreen: 2,
                    nameScreen: "Name 2 of the screen",
                    statusScreen: false
                },
                {
                    idScreen: 3,
                    nameScreen: "Name 3 of the screen",
                    statusScreen: false
                }
        },
        {
            idPlace: 3,
            namePlace: "Name of the place 3",
            typePlace: "Type of the place 3"
            },
            screens: [
                {
                    idScreen: 5,
                    nameScreen: "Name 5 of the screen",
                    statusScreen: false
                },
                {
                    idScreen: 6,
                    nameScreen: "Name 6 of the screen",
                    statusScreen: false
                },
                {
                    idScreen: 7,
                    nameScreen: "Name 7 of the screen",
                    statusScreen: false
                }
        }
    ]
}

And I wanted to modify the value of the attribute 'statusScreen' of the 'idScreen': 5 to true. So I tried the following command (according to the post Updating embedded document property in Mongodb):

db.mycollection.update(  {'places.screens': {$elemMatch: {'idScreen': 5} }},  { $set: { "online": true }},   { multi: true } );

but this creates me an attribute 'online': true in the root of my document and don't modify the value of my desired attribute.

Have you any idea of what is wrong please ?

Best Loic

Community
  • 1
  • 1

1 Answers1

0

In theory you should you positional operator $ to match specific item and update it. But the issue is you need to use two positional operators $ to match position in places and to match position in screens. Unfortunately usage of two positional operators is not yet supported, see there https://jira.mongodb.org/browse/SERVER-831.

So you are unable to update doc in one query.

However you could find all necessary documents by using {'places.screens.idScreen': 5} } query and then update document based on known positions in arrays.

Edit: code to update specific elements in arrays

db.coll.update(
   {'places.screens.idScreen': 5},
   {$set:{"places.0.screens.0.statusScreen":true}} 
)
Andrei Beziazychnyi
  • 2,897
  • 2
  • 16
  • 11
  • Thanks a lot for your really quick answer. So I understood that it's not possible with 2 `$` to access my attribute, I also understood that I can retrieve all documents with {'places.screens.idScreen': 5} but how to modify the nested value of one attribute of my `idScreen:5` please? – LoicDpointgroup May 15 '14 at 08:04
  • Replace set statement with {$set: "places.0.screens.0.statusScreen":true}} or something like this to update specific nested nested item – Andrei Beziazychnyi May 15 '14 at 08:15
  • With `db.mycollection.update( {'places.screens.idScreen': 5}, {$set: "places.0.screens.0.statusScreen": true}}, { multi: true } );` it creates an attribute at the root of my 'screens' sub document. And with : `db.mycollection.update( {'places.screens.idScreen': 72}, {$set: "places.$.screens.0.statusScreen": true}}, { multi: true } );` it changes the value of the first attribute of the screens sub document. I think I am near of the correct solution thanks to you... I need just to find how to retrieve the index position where my 'idScreen':5 is located ... – LoicDpointgroup May 15 '14 at 08:29
  • Query from answer updates first item of first item of screens array. I checked on your data, try to recheck. Don't use positional operator $ without $elemMatch, otherwise it would pick first item from array, so effectively $=0 in your query. – Andrei Beziazychnyi May 15 '14 at 08:35
  • Sorry $=1 in this case – Andrei Beziazychnyi May 15 '14 at 08:42
  • So if I understood, you suggest me to try the command: `db.mycollection.update( {'places.screens': {$elemMatch: {'idScreen': 5} }, {$set: {'places.$.screens.0.statusScreen': true}}, { multi: true } );` OR `db.mycollection.update( {'places.screens': {$elemMatch: {'idScreen': 5} }, {$set: {'places.0.screens.$.statusScreen': true}}, { multi: true } );` ? Because both of them didn't change the nested desired value :(( – LoicDpointgroup May 15 '14 at 09:15
  • I suggest you to find document you need, detect positions in nested documents and update specific items with command I posted in my answer – Andrei Beziazychnyi May 15 '14 at 09:23
  • If I want to change manually the value yes the command: `db.mycollection.update( {'places.screens': {$elemMatch: {'idScreen': 5} }, {$set: {'places.$.screens.0.statusScreen': true}}, { multi: true } );` will work. I am sorry I completely forgot to say you that I wanted to change this value dynamically not fixing the index value directly. That's why I was saying you that I need to find how to retrieve the index position (dynamically) so that I will be able to change the value in one line of code. – LoicDpointgroup May 15 '14 at 09:30
  • It is different story then. Anyway you could not have two dynamic index positions, it is what you are trying to do. – Andrei Beziazychnyi May 15 '14 at 09:42