用mongo $elemMatch 篩選嵌套列表所有符合條件的對象

mongo中存的數據格式如下

// 1
{
    "_id": "1",
    "personCerts": [
        {
            "perId": NumberInt("1"),
            "qualityNum": NumberInt("3"),
            "performance": NumberInt("5"),
            "tenderNum": NumberInt("0"),
            "certifications": [
                {
                    "regType": "LB_051",
                    "regMajor": "ZY_001"
                },
                {
                    "regType": "LB_072",
                    "regMajor": "ZY_006"
                },
                {
                    "regType": "LB_072",
                    "regMajor": "ZY_002"
                }
            ]
        },
        {
            "perId": NumberInt("2"),
            "qualityNum": NumberInt("3"),
            "performance": NumberInt("0"),
            "tenderNum": NumberInt("0"),
            "certifications": [
                {
                    "regType": "LB_072",
                    "regMajor": "ZY_001"
                },
                {
                    "regType": "LB_072",
                    "regMajor": "ZY_006"
                },
                {
                    "regType": "LB_072",
                    "regMajor": "ZY_007"
                }
            ]
        }
    ]
}

當前需求是查詢出該企業人員證書類型爲LB_072,專業爲ZY_001,類型爲LB_072,專業爲ZY_006的人員及其符合條件的證書。通過數據可以知道,該企業只有1人同時擁有這倆本證書,但是如果不用elemmatch,只是使用普通的match,這倆個人都可以被篩選出來,

db.getCollection("company_person_cert_test").aggregate([
    {
        "$match": {
            "_id": "1"
        }
    },
    {
        "$unwind": "$personCerts"
    },
    {
        //這一層是篩選符合條件的人員
        "$match": {
            "$and": [
                {
                    "personCerts.certifications.regType": "LB_072",
                    "personCerts.certifications.regMajor": "ZY_001"
                },
                {
                    "personCerts.certifications.regType": "LB_072",
                    "personCerts.certifications.regMajor": "ZY_006"
                }
            ]
        }
    },
    {
        "$unwind": "$personCerts.certifications"
    },
    {
        //這一層是篩選符合條件的證書(之所以用or,是因爲上一層已經篩選出了符合的人員,
        //所以這一層只需要篩選出該人員符合條件的證書即可)
        "$match": {
            "$or": [
                {
                    "personCerts.certifications.regType": "LB_072",
                    "personCerts.certifications.regMajor": "ZY_001"
                },
                {
                    "personCerts.certifications.regType": "LB_072",
                    "personCerts.certifications.regMajor": "ZY_006"
                }
            ]
        }
    }
])

結果

// 1
{
    "_id": "1",
    "personCerts": {
        "perId": NumberInt("1"),
        "qualityNum": NumberInt("3"),
        "performance": NumberInt("5"),
        "tenderNum": NumberInt("0"),
        "certifications": {
            "regType": "LB_072",
            "regMajor": "ZY_006"
        }
    }
}

// 2
{
    "_id": "1",
    "personCerts": {
        "perId": NumberInt("2"),
        "qualityNum": NumberInt("3"),
        "performance": NumberInt("0"),
        "tenderNum": NumberInt("0"),
        "certifications": {
            "regType": "LB_072",
            "regMajor": "ZY_001"
        }
    }
}

// 3
{
    "_id": "1",
    "personCerts": {
        "perId": NumberInt("2"),
        "qualityNum": NumberInt("3"),
        "performance": NumberInt("0"),
        "tenderNum": NumberInt("0"),
        "certifications": {
            "regType": "LB_072",
            "regMajor": "ZY_006"
        }
    }
}

可以看到,結果並不準確,多了id爲1的人員,這是因爲,id爲1的人員存在類型爲LB_072和專業爲ZY_001的證書(但是並沒有證書同時符合這2個條件),即這種篩選並沒將嵌套的list中的元素當作單獨的對象,所以,我開始嘗試$elemmatch,但是$elemmach一次只能帶出一個符合條件的嵌套對象,百度+google後,依然是overstack給力,可以解決我的需求

https://stackoverflow.com/questions/25014699/mongodb-multiple-elemmatch

根據上述地址,我對我的查詢做出調整

db.getCollection("company_person_cert_test").aggregate([
    {
        "$match": {
            "_id": "1"
        }
    },
    {
        "$unwind": "$personCerts"
    },
    {
        "$match": {
            "$and": [
		{
                    "personCerts.certifications": {
                        "$elemMatch": {
                            "regMajor": "ZY_001",
                            "regType": "LB_072"
                        }
                    }
                },
                {
                    "personCerts.certifications": {
                        "$elemMatch": {
                            "regMajor": "ZY_006",
                            "regType": "LB_072"
                        }
                    }
                }
            ]
        }
    },
    {
        "$unwind": "$personCerts.certifications"
    },
    {
        "$match": {
            "$or": [
                {
                    "personCerts.certifications.regType": "LB_072",
                    "personCerts.certifications.regMajor": "ZY_001"
                },
                {
                    "personCerts.certifications.regType": "LB_072",
                    "personCerts.certifications.regMajor": "ZY_006"
                }
            ]
        }
    }
])

結果

// 1
{
    "_id": "1",
    "personCerts": {
        "perId": NumberInt("2"),
        "qualityNum": NumberInt("3"),
        "performance": NumberInt("0"),
        "tenderNum": NumberInt("0"),
        "certifications": {
            "regType": "LB_072",
            "regMajor": "ZY_001"
        }
    }
}

// 2
{
    "_id": "1",
    "personCerts": {
        "perId": NumberInt("2"),
        "qualityNum": NumberInt("3"),
        "performance": NumberInt("0"),
        "tenderNum": NumberInt("0"),
        "certifications": {
            "regType": "LB_072",
            "regMajor": "ZY_006"
        }
    }
}

ok,正確

在java中這樣寫

Criteria criteria = Criteria.where("_id").is(1);

String[] typeAndMajorArray = "LB_072,ZY_001:LB_072,ZY_006".split(":") ;
Criteria[] criteriaArray = new Criteria[typeAndMajorArray.length];
Criteria[] criteriaArray1 = new Criteria[typeAndMajorArray.length];

for (int i = 0; i < typeAndMajorArray.length ; i++) {
      String regType = typeAndMajorArray[i].split(",")[0];
      String regMajor = typeAndMajorArray[i].split(",")[1];
      criteriaArray[i] = Criteria
                            .where("personCerts.certifications")
                            .elemMatch(Criteria.where("regMajor").is(regMajor).and("regType").is(regType));
      criteriaArray1[i] = Criteria
                            .where("personCerts.certifications.regType").is(regType)
                            .and("personCerts.certifications.regMajor").is(regMajor);
}                  

     Criteria criteria1 = new Criteria();
     Criteria criteria2 = new Criteria();

     criteria1.andOperator(criteriaArray);
     criteria2.orOperator(criteriaArray1);

Aggregation aggregation =
                        newAggregation(
                                match(criteria),
                                unwind("personCerts"),
                                match(criteria1),
                                limit(10),
                                unwind("personCerts.certifications"),
                                sort(new Sort(Sort.Direction.DESC,"major")),
                                match(criteria2)
                        );

return mongoTemplate.aggregate(aggregation, collectionName,JSONObject.class)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章