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)