I have a collection like this:
{
"_id" : XXXXX,
"players" : [
{
"name": xxx,
"status" : 0,
...
},
{
"name": xxx,
"status" : 1,
...
},
...
],
"else":XXXXX
}
{
"_id" : XXXXX,
"players" : [
{
"name": xxx,
"status" : 0,
...
},
{
"name": xxx,
"status" : 0,
...
},
...
],
"else":XXXXX
}
I want to find all the documents that in the Players array, all the status is 0. I tried db.data.find({"players.status":{$all :[0]}})
and db.data.find({"players":{$elemMatch : { "status" : 0}}})
those only give me documents that contain an array field with at least one elements that matches all the specified query criteria.
What can I do???
Based on your document, I created a collection with below documents.
{
"_id" : 1,
"players" : [
{
"name" : 11,
"status" : 0
},
{
"name" : 22,
"status" : 1
}
]
}
{
"_id" : 2,
"players" : [
{
"name" : 33,
"status" : 0
},
{
"name" : 44,
"status" : 0
}
]
}
The elemsMatch filter return all the array elements when one of the elements match the filter criteria - http://docs.mongodb.org/manual/reference/operator/query/elemMatch
You can use use elemMatch with projection, to return only a single element from the array - https://docs.mongodb.org/manual/reference/operator/projection/elemMatch/
db.data.find({"players.status" : 0},{"players":{$elemMatch : { "status" : 0}}})
The above query will return one array element for each document.
{ "_id" : 1, "players" : [ { "name" : 11, "status" : 0 } ] }
{ "_id" : 2, "players" : [ { "name" : 33, "status" : 0 } ] }
But if you expect multiple array elements to match the criteria, then you can use below Aggregation query.
db.data.aggregate([
// 3rd step will do the work, but for performence benefit - Match to reduce the docs which has one or more array elements with players.status = 0
{$match : { "players.status" : 0 }},
// Unwind the players array
{$unwind : "$players"},
// Match players.status = 0
{$match : { "players.status" : 0 }},
// Group the docs based on _id and push the players doc(from unwind) with status = 0, to the players array
{ "$group": {
"_id": "$_id",
"players": { "$push": "$players" }
}}
])
The result of above aggragtion query is -
{ "_id" : 1, "players" : [ { "name" : 11, "status" : 0 } ] }
{ "_id" : 2, "players" : [ { "name" : 33, "status" : 0 }, { "name" : 44, "status" : 0 } ] }
您需要将$all
与$elemMatch
结合起来,这样的事情可能会$elemMatch
:
db.data.find({ "players": { "$all": { "$elemMatch": { "status": 0 } } } });
I found a easy but silly way to solve my question but I still want to know if there is a easy way to do it.
If I know exactly how may items in players array ,I can $and all them together to get what I want, for example, if I have 10 items in players array. I can do this:
db.data.find({
$and :[
{"players.0.status" : 0},
{"players.1.status" : 0},
{"players.2.status" : 0},
{"players.3.status" : 0},
{"players.4.status" : 0},
{"players.5.status" : 0},
{"players.6.status" : 0},
{"players.7.status" : 0},
{"players.8.status" : 0},
{"players.9.status" : 0}
]
})
But what should I do if I have more items in players array?
You could use the $not
operator : https://docs.mongodb.com/manual/reference/operator/query/not/#op._S_not
db.data.find({"player.status": { $elemMatch: { $ne: 0 }}})
would give you all the payers that have at least one status different from 0.
Then db.data.find({"player.status": {$not: { $elemMatch: { $ne: 0 }}}})
would give you all the players that have all their statuses equal 0
i ended up with the following solution for this problem:
db.data.find({
"players": {
"$not": {
"$elemMatch": {
"status": { "$ne": 0 }
}
}
}
})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.