0

I have a Mongodb document that contains an an array that is deeply imbedded inside the document. In one of my action, I would like to return the entire document but filter out the elements of that array that don't match that criteria.

Here is some simplified data:

{
   id: 123 ,
   vehicles : [
     {name: 'Mercedes', listed: true},
     {name: 'Nissan', listed: false},
     ...
   ]
}

So, in this example I want the entire document but I want the vehicles array to only have objects that have the listed property set to true.

Solutions

Ideally, I'm looking for a solution using mongo's queries (e.g. `$unwind, $elemMatch, etc...) but I'm also using mongoose so solution that uses Mongoose is OK.

2 Answers 2

3

You could use aggregation framework like this:

db.test312.aggregate(
    {$unwind:"$vehicles"},
    {$match:{"vehicles.name":"Nissan"}},
    {$group:{_id:"$_id",vehicles:{$push:"$vehicles"}}}
)
Sign up to request clarification or add additional context in comments.

4 Comments

How to I keep properties inside the main object? (e.g. { id: 123 , name: 'testName', vehicles : [ ... ] })
Either by adding fields to {$group:{_id:{_id:"$_id",name:"$name"}}, vehic...} or by using {_id:"$_id",name:{$last:"$name"},vehic..}. In first case you need to add {$project:{}} after {$group} to unwrap _id
Thanks, I was kinda going the second way, but the first seems a bit cleaner
Actually I've encountered problem with that method: Follow-up: stackoverflow.com/questions/23636175/…
1

You can use $addToSet on the group after unwinding and matching by listed equals true.

Sample shell query:

db.collection.aggregate([
{
    $unwind: "$vehicles"
},
{
    $match: {
        "vehicles.listed": {
            $eq: true
        }
    }
},
{
    $group: {
        _id: "$id",
        vehicles: {
            "$addToSet": {
                name: "$vehicles.name",
                listed: "$vehicles.listed"
            }
        }
    }
},
{
    $project: {
        _id: 0,
        id: "$_id",
        vehicles: 1
    }
}
]).pretty();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.