Spring 数据 MongoDB - 与其他集合的聚合

Spring Data MongoDB - Aggregation with other collection as well

我正在研究 Spring Boot v.2.1.3.RELEASE 和 Spring Data MongoDB。由于关键要求,我必须像下面这样建模,假设员工知道多种技术,但主要语言是任何人。

因此,我决定将技术集合分开,并在员工集合中以某种方式关联员工和技术。

{
    "_id" : ObjectId("5ec65750fdcd4e960f4b2f24"),
    "technologyCd" : "AB",
    "technologyName" : "My ABC",
    "ltechnologyNativeName" : "XY",
    "status" : "A"
}

所以,我完成了如下关联 -

Note: Multiple Technologies can be associated with one Employee

One Employee can be associated with multiple technologies

Employee can have one and only one Primary Technology

{
    "_id" : ObjectId("5ec507c72d8c2136245d35ce"),
    "firstName" : "John",
    "lastName" : "Doe",
    "email" : "j.d@gmail.com",
    .......
    .......
    .......
    "employeeTechnologyRefs" : [ 
        {
            "technologyCd" : "AB",
            "primaryTechnologySw" : "Y",
            "Active" : "A"
        }, 
        {
            "technologyCd" : "AB",
            "primaryTechnologySw" : "N",
            "Active" : "A"
        }, 
        {
            "technologyCd" : "PR",
            "primaryTechnologySw" : "N",
            "Active" : "A"
        }, 
        {
            "technologyCd" : "PR",
            "primaryTechnologySw" : "N",
            "Active" : "A"
        }
    ],
    "countryPhoneCodes" : [ 
        "+352"
    ],
    ....
    ...
}

我使用了以下查询,如何查询技术文档以获得结果并将其映射并创建最终对象?

Criteria criteria = new Criteria();
criteria.andOperator(
        StringUtils.isNotBlank(firstName) ? Criteria.where("firstName").is(firstName.toUpperCase())
                : Criteria.where(""),
        StringUtils.isNotBlank(lastName) ? Criteria.where("lastName").is(lastName.toUpperCase())
                : Criteria.where(""),
        StringUtils.isNotBlank(email) ? Criteria.where("email").is(email.toUpperCase())
                : Criteria.where(""),
        StringUtils.isNotBlank(technologyCd) ? Criteria.where("employeeTechnologyRefs.technologyCd").is(technologyCd.toUpperCase())
                : Criteria.where(""));

MatchOperation matchStage = Aggregation.match(criteria);

GroupOperation groupOp = Aggregation
        .group("firstName", "lastName", "email","_id")
        .addToSet("employeeTechnologyRefs").as("employeeTechnologyRefs");

ProjectionOperation projectStage = Aggregation.project("employeeTechnologyRefs");

Aggregation aggregation = Aggregation.newAggregation(matchStage, groupOp, projectStage);

AggregationResults<CustomObject> results = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Employee.class), CustomObject.class);
System.out.println(results);

结果应如下所示

{
    "_id" : ObjectId("5ec507c72d8c2136245d35ce"),
    "firstName" : 442,
    "lastName" : "LU",
    "email" : "LUX",
    .......
    .......
    .......
    "employeeTechnologyRefs" : [ 
        {
            "technologyCd" : "AB",
            "technologyName" : "My ABC",
            "ltechnologyNativeName" : "XY",
            "primaryTechnologySw" : "Y",
            "Active" : "A"
        }, 
        {
            "technologyCd" : "AB",
            "technologyCd" : "AB",
            "technologyName" : "My ABC",
            "ltechnologyNativeName" : "XY",
            "primaryTechnologySw" : "Y",
            "Active" : "A"
        }, 
        {
            "technologyCd" : "PR",
            "technologyCd" : "AB",
            "technologyName" : "My ABC",
            "ltechnologyNativeName" : "XY",
            "primaryTechnologySw" : "Y",
            "Active" : "A"
        }, 
        {
            "technologyCd" : "PR",
            "technologyCd" : "AB",
            "technologyName" : "My ABC",
            "ltechnologyNativeName" : "XY",
            "primaryTechnologySw" : "Y",
            "Active" : "A"
        }
    ],
    ....
    
}

如果您在代码中使用以下查找操作,您应该可以得到预期的答案,并且您的代码中不需要组操作。

编辑后的答案:这就是整个代码的样子。还有一件事,您不需要投影,如果您只需要尝试投影特定字段,并且作为查找操作的一部分,请不要使用与集合中相同的字段,否则它将覆盖员工集合中的现有数据。

    Criteria criteria = new Criteria();
    criteria.andOperator(
            StringUtils.isNotBlank(firstName) ? Criteria.where("firstName").is(firstName.toUpperCase())
                    : Criteria.where(""),
            StringUtils.isNotBlank(lastName) ? Criteria.where("lastName").is(lastName.toUpperCase())
                    : Criteria.where(""),
            StringUtils.isNotBlank(email) ? Criteria.where("email").is(email.toUpperCase())
                    : Criteria.where(""),
            StringUtils.isNotBlank(technologyCd) ? Criteria.where("employeeTechnologyRefs.technologyCd").is(technologyCd.toUpperCase())
                    : Criteria.where(""));

    MatchOperation matchStage = Aggregation.match(criteria);

    /*GroupOperation groupOp = Aggregation
            .group("firstName", "lastName", "email","_id")
            .addToSet("employeeTechnologyRefs").as("employeeTechnologyRefs");
            */

    LookupOperation lookupOperation = LookupOperation.newLookup().
                                     from("technology_collection_name").
                                     localField("employeeTechnologyRefs.technologyCd").
                                     foreignField("technologyCd").
                                     as("employeeTechnologyRefsOtherName");

   /* ProjectionOperation projectStage = Aggregation.project("employeeTechnologyRefs");
  */  
// And if you want to project specific field from employee array you can use something like.
ProjectionOperation projectStage = Aggregation.project("employeeTechnologyRefs.fieldName")
    Aggregation aggregation = Aggregation.newAggregation(matchStage, lookupOperation, projectStage);

    AggregationResults<CustomObject> results = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Employee.class), CustomObject.class);
    System.out.println(results);