Spring Data MongoDB - Aggregation with other collection as well

ε祈祈猫儿з 提交于 2020-05-23 11:54:51

问题


I'm working on Spring Boot v.2.1.3.RELEASE and Spring Data MongoDB. Due to critical requirement, I had to model like below assuming Employee knows multiple technologies, but primary language would be anyone.

So, I decided to keep technology collection separate and somehow related Employee and technology in the Employee Collection.

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

So, I've done association like below -

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"
    ],
    ....
    ...
}

I used below query, how to query over the Technology documents to get the result and map it and create final object?

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);

Result should look like below

{
    "_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"
        }
    ],
    ....

}

回答1:


If you use below lookup operation in your code, you should able to get the answer as expected, and you don't need group operation in your code.

Edited Answer: This is how whole code should look like. One more thing, you don't need projection and if you need try projecting specific field only, and as part of the lookup operation do not use the same field as it is in your collection, otherwise it will override existing data from employee collection.

    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").
                                     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);


来源:https://stackoverflow.com/questions/61953464/spring-data-mongodb-aggregation-with-other-collection-as-well

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!