Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using $pull in Mongodb to remove a deeply embedded object

I'm trying to delete ($pull) an object from an array that's embedded. (Using javascript/node.js driver.)

Here is the sample data, where one, two, three are the levels:

{
    one : "All",
    one : [
        {
        name: "People",
        two: [
            { 
            three_id: 123,
            three: "Jonny",
            },
            { 
            three_id: 456,
            three: "Bobby",
            }
        ]
        },
        {
        name: "Animals",
        two: [
            { 
            three_id: 828,
            three: "Cat",
            },
            { 
            three_id: 282,
            three: "Dog",
            }
        ]
        }
    ]   
}

In this example, I'm trying get rid of "Bobby".

I can successfully match the document at the "three level" if I want, like this:

db.test.find({"one.two.three_id" : 456});

However, I've no idea how to eliminate that record using update. Here are some attempts, none of which work:

// failed attempts
db.test.update({"one.two.three_id" : 456}, {$pull:{'one.$.two.$.three_id': 456}});
db.test.update({"one.two.three_id" : 456}, {$pull:{'three_id': 456}});

// deletes entire level two "People"
db.test.update({"one.two.three_id" : 456}, {$pull: {one: {two : {$elemMatch: {'three_id': 456}}}}});

I read that you cannot use two positional $ operators and that you have to know the index position for the second one. However, I want to avoid having to use the index of the embedded dictionary I want to delete.

reference: Mongodb on pull

http://docs.mongodb.org/manual/reference/operator/update/pull/

like image 863
cathy.sasaki Avatar asked Oct 17 '13 19:10

cathy.sasaki


1 Answers

The value of the key in your $pull object needs to be the path of the array that you're targeting. This appears to work:

db.test.update(
    {'one.two.three_id': 456},
    {$pull: {'one.$.two': {three_id: 456}}}
);

It looks like the $ represents the index of the first matched array level in this case so it works even though we're matching across multiple nesting levels.

like image 66
JohnnyHK Avatar answered Nov 14 '22 22:11

JohnnyHK