11

I'm looking at MongoDB's documentation on the $ and $elemMatch projections. I'm trying to figure out how to return only a subset of a projection array's fields, but I cannot seem to figure it out.

Related posts:

Say I have the following documents in the test collection:

{
    "_id": "A",
    "array": [
        {"key": 1, "name": "foo", "data": {}},
        {"key": 2, "name": "bar", "data": {}}
    ],
    "extra": {}
},
{
    "_id": "B",
    "array": [
        {"key": 3, "name": "spam", "data": {}},
        {"key": 4, "name": "eggs", "data": {}}
    ],
    "extra": {}
}

The query I effectively want to perform is:

db.test.findOne({"array.key": 1}, {"array.$.name": 1, "extra": 1})

Which I would expect it to only return name under the sub-document in the array where key was 1. E.g.,

{
    "_id": "A",
    "array": [
        {"name": "foo"}
    ],
    "extra": {}
}

But if I perform that query, I get this instead:

{
    "_id": "A",
    "array": [
        {"key": 1, "name": "foo", "data": {}}
    ],
    "extra": {}
}

Which is identical to doing the query:

db.test.findOne({"array.key": 1}, {"array.$": 1, "extra": 1})

I've also tried the following which results in the same:

db.test.findOne({"array.key": 1}, {"array.$": 1, "array.name": 1, "extra": 1})

Is there a way to only return a subset of the fields for array.$ instead of the whole sub-document?

1 Answer 1

9

Are you specifically trying to do this without using aggregate?

db.test.aggregate([{$unwind:"$array"},
                   {$match:{"array.key":1}},
                   {$project:{"array.name":1, extra:1}}])
Sign up to request clarification or add additional context in comments.

2 Comments

I wasn't aware that aggregation could accomplish what I was trying to do because I'm not aggregating multiple documents.
But what if you can't use aggregates? I'm a little confused about this, given that you can use the $ operator and access a subfield in an update like this: db.students.update( { _id: 4, "grades.grade": 85 }, { $set: { "grades.$.std" : 6 } } )

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.