Reputation: 53
I have a document like this..
{
"_id" : ObjectId("59b0ea9b3a91af574a3e0464"),
"machineID" : "b83c",
"sensorState" : [
{
"data" : "377",
"sensor" : "solar",
"time" : ISODate("2017-09-20T19:42:58.766Z")
},
{
"data" : "35",
"sensor" : "photosynthetic",
"time" : ISODate("2017-09-20T19:42:58.782Z")
},
{
"data" : "370",
"sensor" : "solar",
"time" : ISODate("2017-09-20T19:43:29.089Z")
},
{
"data" : "400",
"sensor" : "solar",
"time" : ISODate("2017-09-20T19:44:29.089Z")
},
{
"data" : "35",
"sensor" : "photosynthetic",
"time" : ISODate("2017-09-20T19:43:29.110Z")
}
]
}
I want to retrieve only those sub documents in the sensorState
array which match sensor=solar
. So, I tried to do like this:
db.getCollection('sensorDB').find({ },
{ "sensorState" : { $elemMatch: {data : "35" } } })
But it shows only one result:
{
"_id" : ObjectId("59b0ea9b3a91af574a3e0464"),
"sensorState" : [
{
"data" : "35",
"sensor" : "photosynthetic",
"time" : ISODate("2017-09-20T19:42:58.782Z")
}
]
}
However, I want to find all sub documents in the sensorState
array which match sensor=solar
. It looks like $elemMatch
just can select one result.
Upvotes: 2
Views: 2346
Reputation: 53
I found answer myself. use aggregate the answer is like this
db.getCollection('sensorDB').aggregate(
{$match: {machineID:"b83c"}},
{$unwind:"$sensorState"},
{$match: {"sensorState.sensor":"solar"}}
)
Upvotes: 3
Reputation: 48015
You are attempting to project with elemMatch but according to the docs
The
$elemMatch
operator limits the contents of an field from the query results to contain only the first element matching the$elemMatch
condition.
So, the behaviour you are seeing is the expected behaviour for elemMatch-in-a-projection.
You can get use $project
and $filter
in an aggregation pipeline to get your end result.
Given the sample document included in your OP the following command ...
db.getCollection('elemMatch').aggregate([
// projects on the sensorState sub documents and filters the output to only return sub
// documents having data=35
{$project: {
sensorState: {
$filter: {
input: "$sensorState",
as: "sensorState",
cond: { $eq: [ "$$sensorState.data", '35' ] }
}
}
}
}
])
... will return:
{
"_id" : ObjectId("59b0ea9b3a91af574a3e0464"),
"sensorState" : [
{
"data" : "35",
"sensor" : "photosynthetic",
"time" : ISODate("2017-09-20T19:42:58.782Z")
},
{
"data" : "35",
"sensor" : "photosynthetic",
"time" : ISODate("2017-09-20T19:43:29.110Z")
}
]
}
Your questions shows an attempted match on data=35
but it also states:
I want to find all sensorState.sensor = solar
So, here's the above command with that condition:
db.getCollection('elemMatch').aggregate([
// projects on the sensorState sub documents and filters the output to only return sub
// documents having sensor=solar
{$project: {
sensorState: {
$filter: {
input: "$sensorState",
as: "sensorState",
cond: { $eq: [ "$$sensorState.sensor", 'solar' ] }
}
}
}
}
])
Which returns:
{
"_id" : ObjectId("59b0ea9b3a91af574a3e0464"),
"sensorState" : [
{
"data" : "377",
"sensor" : "solar",
"time" : ISODate("2017-09-20T19:42:58.766Z")
},
{
"data" : "370",
"sensor" : "solar",
"time" : ISODate("2017-09-20T19:43:29.089Z")
},
{
"data" : "400",
"sensor" : "solar",
"time" : ISODate("2017-09-20T19:44:29.089Z")
}
]
}
Upvotes: 1