Reputation: 155
I'm a bit lost in the querying of subdocumnents.
Consider the following collection of things:
{
name: "thing1",
gadgets:
[
{
name: "gadget1",
components: [
{
name: "component1"
properties:
[
{id: "I1", value: "V1"}, {id: "I2", value: "V2"},
{id: "I3", value: "V3"}, {id: "I4", value: "V2"},...
]
},
{
name: "component2"
properties:
[
{id: "I1", value: "V1"}, {id: "I2", value: "V4"},
{id: "I3", value: "V3"}, {id: "I4", value: "V5"},...
]
}
]
},
{
name: "gadget2",
components: [
{
name: "component1"
properties:
[
{id: "I1", value: "V1"}, {id: "I2", value: "V3"},
{id: "I3", value: "V3"}, {id: "I4", value: "V2"},...
]
},
{
name: "component2"
properties:
[
{id: "I1", value: "V1"}, {id: "I2", value: "V7"},
{id: "I3", value: "V1"}, {id: "I4", value: "V2"},...
]
}
]
}
]
}
I want to query the collection and get all things that contains gadgets with name "gadget1" and that contains in the components array a document with the name "component1", the "component1"-subdocumnent should also contain in the properties array both the documents:
{id: "I1", value: "V1"} and {id: "I2", value: "V2"}.
Is this possible with a query?
I have tried with the following query:
{ "$and": [{"gadgets.name": "gadget1"}{"gadgets.properties.id": "I1", "gadgets.properties.value": "V1"},{"gadgets.properties.id": "I2", "gadgets.properties.value": "V2"}]}
But with no success.
Upvotes: 1
Views: 124
Reputation: 50406
So there are a couple of things here. This is actually a case for $and
, and it often isn't needed, but it is needed when you need multiple conditions on the same object path. And also to match multiple properties on a an array sub-document you need $elemMatch
:
db.collection.find({
"$and": [
{
"components.properties": {
"$elemMatch": {
"id": "I1", "value": "V1"
}
}
},
{
"components.properties": {
"$elemMatch": {
"id": "I2", "value": "V2"
}
}
}
]
})
That will tell you where a document has "both" array elements in "components.properties"
that actually match both sets of conditions.
Thinking about that more, you can actually use $all
here, in combination with $elemMatch
:
db.collection.find({
"components.properties": {
"$all": [
{ "$elemMatch": {
"id": "I1", "value": "V1"
}},
{ "$elemMatch": {
"id": "I2", "value": "V2"
}}
]
}
})
And that is a much cleaner and readable format. An $all
is basically another form of $and
that you can use to specify the condition on the same key that applies to this particular format.
Upvotes: 2