1

I have a document with the following structure (simplified):

{
    "containers": [
    {
        "containerId": 1,
        "components": ["component1", "component2"]
    },
    {
        "containerId": 2,
        "components": ["component3", "component1"]
    }]
}

How would one write a query that removes "component1" from BOTH containers? Is this possible?

So far I've tried doing {"$pullAll": { "containers.$.component": ["component1"]}}, a similar query with $pull, setting multi: true but I always end up removing the component from the first array only (I'm using .update())

EDIT: Raw data ahead!

{
    "_id" : ObjectId("53a056cebe56154c99dc950b"),
    "_embedded" : {
        "click" : {
            "items" : [],
            "_links" : {
                "self" : {
                    "href" : "http://localhost/v1/click"
                }
            }
        },
        "container" : {
            "_links" : {
                "self" : {
                    "href" : "http://localhost/v1/container"
                }
            },
            "items" : [ 
                {
                    "name" : "Container test",
                    "uriName" : "Container_test",
                    "description" : "this is a test container",
                    "containerId" : "CONTAINER TEST+SITE_TEST",
                    "component" : [ 
                        "ANOTHER COMPONENT+SITE_TEST", 
                        "ANOTHER COMPONENT+SITE_TEST", 
                        "SARASA+SITE_TEST"
                    ],
                    "_links" : {
                        "self" : {
                            "href" : "http://localhost/v1/container/CONTAINER TEST+SITE_TEST"
                        }
                    }
                }, 
                {
                    "name" : "sasasa",
                    "uriName" : "sasasa",
                    "description" : "container description",
                    "containerId" : "SASASA+SITE_TEST",
                    "component" : [ 
                        "ANOTHER COMPONENT+SITE_TEST", 
                        "COMPONENT+SITE_TEST", 
                        "FAFAFA+SITE_TEST", 
                        "SARASA+SITE_TEST"
                    ],
                    "_links" : {
                        "self" : {
                            "href" : "/v1/container/SASASA+SITE_TEST"
                        }
                    }
                }
            ]
        }
    },
    "name" : "SITE_TEST",
    "siteId" : "SITE_TEST",
    "url" : "/v1/site"
}

Ok, so what I'm trying to do is remove the component "SARASA+SITE_TEST" from the two containers. I'm using robomongo to test the queries. I've tried db.site.update({"_embedded.container.items.component": "SARASA+SITE_TEST"},{"$pullAll": { "_embedded.container.items.component": ["SARASA+SITE_TEST"]}}, {multi: true}) and it didn't work, previously I've tried db.site.update({"_embedded.container.items.component": "SARASA+SITE_TEST"},{"$pull": { "_embedded.container.items.$.component": "SARASA+SITE_TEST"}}, {"multi": true}) and it didn't work either. I assume robomongo exposes the mongo driver directly, I didn't try to run this from the command line.

(the document is a "site", that's why my queries start with db.site)

Pablo Mescher
  • 26,057
  • 6
  • 30
  • 33
  • $pull with multi: true should work. How does your .update() look like? Are you doing it from mongo shell or in the code? If in the code, which driver are you using? – Ben Jun 23 '14 at 14:11
  • Are you getting this json as a response from some service ? This is of the form { "containers" : json_array}. I tried out and it seems that $pull doesn't work on nested array i.e "containers.components". However, if you apply this query on just json_array, it returns expected result. db.collection.update( { "components": "component1" }, { $pull: { "components": "component1" } }, { multi: true } ). – Tushar Mishra Jun 23 '14 at 14:18
  • @TusharMishra I'm not following you. Please see my edit. I tried doing db.site.update({"component": "SARASA+SITE_TEST"},{"$pull": { "component": "SARASA+SITE_TEST"}}, {"multi": true}) and it didn't work, although it executed successfully. – Pablo Mescher Jun 23 '14 at 14:57
  • 1
    I think this question goes back to: "how to update multiple elements in an array?", no matter whether it is a nested array or not.Well, the question has already been asked on stackoverflow, [here](http://stackoverflow.com/questions/4669178/how-to-update-multiple-array-elements-in-mongodb) and the answer is: no. But there are some workarounds (see the link). – dgiugg Jun 23 '14 at 15:13
  • @dgiugg this might very well be the issue. So sad to know mongodb doesn't support this.. although I concede I'm not very happy with the data model as it is right now (not that I can change it though) – Pablo Mescher Jun 23 '14 at 15:35

2 Answers2

0

I had a similar problem and I tried $pullAll and it worked.

https://docs.mongodb.org/manual/reference/operator/update/pullAll/

-1

I tried the simplified version of your data and $pull works:

> db.testcoll.insert({"containers": {"containreId": 1, "components": ["component1", "component2"]}})
> db.testcoll.insert({"containers": {"containreId": 2, "components": ["component3", "component1"]}})
> db.testcoll.find()
{ "_id" : ObjectId("53a8428ca2696f063b5c51eb"), "containers" : { "containreId" : 1, "components" : [  "component1",  "component2" ] } }
{ "_id" : ObjectId("53a8429ea2696f063b5c51ec"), "containers" : { "containreId" : 2, "components" : [  "component3",  "component1" ] } }
> db.testcoll.update({"containers.components": "component1"}, {$pull: {"containers.components": "component1"}}, {multi: true})
> db.testcoll.find()
{ "_id" : ObjectId("53a8428ca2696f063b5c51eb"), "containers" : { "components" : [  "component2" ], "containreId" : 1 } }
{ "_id" : ObjectId("53a8429ea2696f063b5c51ec"), "containers" : { "components" : [  "component3" ], "containreId" : 2 } }
Ben
  • 5,024
  • 2
  • 18
  • 23