How to request documents where an array has a field more than n times in MongoDB

I have a MongoDB collection worldwith documents in the following format:

{
  _id : ObjectId("4e8ae86d08101908e1000001"),
  country : [
      {
          state: "Newyork",
          type: 1
      },
      {
          state: "California",
          type: 1
      },
      {
          state: "Texas",
          type: 2
      }
  ]
}

We can easily get documents that have four or more states:

db.world.find({'country.4': {$exists: true} })

But how can I get documents in which an array of countries has four or more states type: 1?

In addition, I want to avoid the operator $wherein the request.

Change 1

The answer to this question by Blakes Seven seems correct to me, but when I try to do the opposite ie; get documents with less than n fields, then I get erroneous results:

Here is the request:

db.world.aggregate([
    { "$redact": {
        "$cond": {
            "if": {
                "$lte": [
                    { "$size": { "$setDifference": [
                        { "$map": {
                            "input": "$country",
                            "as": "el",
                            "in": {
                                "$cond": {
                                    "if": { "$eq": [ "$$el.type", 769 ] },
                                    "then": "$$el",
                                    "else": false
                                }
                            }
                        }},
                        [false]
                    ]}},
                    4
                ]
            },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}
]);
+4
source share
1

"" , , . $size $redact.

$setIsSubset, , , "" . , :

"$setIsSubset": [[1,0],[1]]

, , false. , , , ( 0), "" "" . "" , :

"$setIsSubset": [[1],[1]]

, , "" .

, "", :

db.world.aggregate([
    { "$match": { "country.3": { "$exists": true } }},
    { "$redact": {
        "$cond": {
            "if": {
                "$gte": [
                    { "$size": { "$setDifference": [
                        { "$map": {
                            "input": "$country",
                            "as": "el",
                            "in": {
                                "$cond": {
                                    "if": { "$eq": [ "$$el.type", 1 ] },
                                    "then": "$$el",
                                    "else": false
                                }
                            }
                        }},
                        [false]
                    ]}},
                    4
                ]
            },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}
])

, "set" $setDifference, false , . $size, , $$PRUNE, .

$map , , false , .

, , , , "", MongoDB $filter, , , "set":

db.world.aggregate([
    { "$match": { "country.3": { "$exists": true } }},
    { "$redact": {
        "$cond": {
            "if": {
                "$gte": [
                    { "$size": { "$filter": {
                        "input": "$country",
                        "as": "el",
                        "cond": {
                            "$eq": [ "$$el.type", 1 ]
                        }
                    }}},
                    4
                ]
            },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}
])

, , , , $unwind $match , "" $group:

db.world.aggregate([
    { "$match": { "country.3": { "$exists": true } }},
    { "$project": { "country": 1, "countryCopy": "$country" } },
    { "$unwind": "$country" },
    { "$match": { "country.type": 1 } },
    { "$group": {
        "_id": "$_id",
        "country": { "$first": "$countryCopy" }
        "count": { "$sum": 1 }
    }},
    { "$match": { "count": { "$gte": 4 } }}
])

, , , .

$match, , ( n-1), , , , 4 .

$exists , . , - .

+3

Source: https://habr.com/ru/post/1611420/


All Articles