简体   繁体   中英

How to find documents that contain an array field with all elements that matches all the specified query criteria

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM