개발/TIL

mongodb aggregation Spring Data MongoDB 에서 사용하기 (mappedResults - 클래스 매핑)

ebang 2025. 2. 14. 22:00

Spring Data MongoDB

Spring Data JPA 와 다르다. 

 

JPA 와 다르기 때문에 프로젝트 내에서 mongoDB가 아니라 RDB, 예를들어 Mysql을 위해서 Spring Data JPA 를 함께 사용할 경우 transaction 이 되는 방식 등등이 다르기 때문에 주의가 필요하다. 

 

각설하고,  이 프레임워크를 이용해서 mongodb aggregation 수행 시 입력한 class 에 대해 mapping 된 결과를 mappedResults 필드에 저장하도록 할 수 있다.

 

 

 

이렇게 사용하면 mappedResult 에 알아서 클래스의 필드에 매핑이 되는 것이다. 

class TagCount {
 String tag;
 int n;
}


import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

Aggregation agg = newAggregation(
    project("tags"),
    unwind("tags"),
    group("tags").count().as("n"),
    project("n").and("tag").previousOperation(),
    sort(DESC, "n")
);

AggregationResults<TagCount> results = mongoTemplate.aggregate(agg, "tags", TagCount.class);
List<TagCount> tagCount = results.getMappedResults();

 

그때 매핑 시에는 기본적으로 필드 이름이 같은 데이터에 대해서 매핑이되는데, 그렇지 않은 경우에는 다음과 같은 지원을 이용해서 설정할 수 있다.

 

1. @Field 어노테이션

class ZipInfo {
   String id;
   String city;
   String state;
   @Field("pop") int population;
   @Field("loc") double[] location;
}

 

이렇게 사용하면 aggregation후 mappedResults 에 "pop" 이름을 가진 데이터가 population 필드에 매핑된다. 

 

2. Nested class 매핑 지원

class ZipInfo {
   String id;
   String city;
   String state;
   @Field("pop") int population;
   @Field("loc") double[] location;
}

class City {
   String name;
   int population;
}

class ZipInfoStats {
   String id;
   String state;
   City biggestCity;
   City smallestCity;
}
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

TypedAggregation<ZipInfo> aggregation = newAggregation(ZipInfo.class,
    group("state", "city")
       .sum("population").as("pop"),
    sort(ASC, "pop", "state", "city"),
    group("state")
       .last("city").as("biggestCity")
       .last("pop").as("biggestPop")
       .first("city").as("smallestCity")
       .first("pop").as("smallestPop"),
    project()
       .and("state").previousOperation()
       .and("biggestCity")
          .nested(bind("name", "biggestCity").and("population", "biggestPop"))
       .and("smallestCity")
          .nested(bind("name", "smallestCity").and("population", "smallestPop")),
    sort(ASC, "state")
);

AggregationResults<ZipInfoStats> result = mongoTemplate.aggregate(aggregation, ZipInfoStats.class);
ZipInfoStats firstZipInfoStats = result.getMappedResults().get(0);

 

Spring Data MongoDB는 내부 class 를 nested 방식으로 매핑을 지원한다. 따라서 별도의 설정없이 지원받을 수 있기 때문에 간편하다는 장점이 있다. 

 

 

 

관련 문서 : https://docs.spring.io/spring-data/mongodb/reference/mongodb/aggregation-framework.html

 

Aggregation Framework Support :: Spring Data MongoDB

abs, acos, acosh, add (* via plus), asin, asin, atan, atan2, atanh, ceil, cos, cosh, derivative, divide, exp, floor, integral, ln, log, log10, mod, multiply, pow, round, sqrt, subtract (* via minus), sin, sinh, tan, tanh, trunc

docs.spring.io