본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


몽고DB/Java 몽고DB

MongoTemplate Aggregate 2 (lookup, unwind,first,last,push ..)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2019. 9. 6.

 

 

MongoDBAggregates.java
0.01MB

몽고db에서 자주 사용되는 집계함수 기능에 대해서 정리하여 보았다.

 

1. body 컬렉션 내용은 아래와 같다.

 

2. head 컬렉션 내용이다.

 

3. 단순 집계 기능이다. 조회, 그룹핑, 카운트 및 합계이다. 대상은 body 컬렉션이다. as 메소드는 불리우는 이름이다.

	public void simpleSingle(){
		Aggregation agg = null;
		AggregationResults<HashMap> results = null;
		agg = Aggregation.newAggregation(
			Aggregation.project()  //1. 매핑할 이름
				.and("text").as("text_conv")  //2.기존 도큐먼트 이름 바꾸기 가능
				.and("type").as("type")
				.and("date").as("date")
				.and("number").as("number"),
			Aggregation.match(     //3. 날짜비교 
				new Criteria().andOperator(
						Criteria.where("date").gte(LocalDateTime.parse("2019-09-01T00:00:00")).lte(LocalDateTime.parse("2019-09-30T23:59:59"))
					)
			),
			Aggregation.group("type").count().as("total").sum("number").as("number")  //4.그룹핑할 대상, 각 대상의 총 합은 total로 한다. number는 합계
		);
		results = template.aggregate(agg, "body", HashMap.class);
		if(results != null){
			List<HashMap> target = results.getMappedResults();
			target.forEach(System.out::println);
		}
	}

첫번째 메소드 결과

 

4. first와 last를 포함한 메소드이다. 집계하는 컬렉션 대상을 그룹할 때 가장 처음값과 마지막 값을 묶어준다.

	public void simpleFirstAndLast(){
		Aggregation agg = null;
		AggregationResults<HashMap> results = null;
		agg = Aggregation.newAggregation(
			Aggregation.project()  //1. 매핑할 이름
				.and("1").as("1")  //2. 1을 준 이유는 집계하는 대상이 1개면 불필요한 매핑이 되는 버그가 있다. 결과에는 아무런 문제 없다.
				.and("text").as("text_conv")  //3. 기존 도큐먼트 이름 바꾸기 가능
				.and("type").as("type")
				.and("date").as("date")
				.and("number").as("number"),
			Aggregation.match(     //4. 조건 null이 아닌것 
				new Criteria().andOperator(
						Criteria.where("text_conv").ne(null)
					)
			),
			Aggregation.group("type","1")                                         //5. type으로 그룹핑 하되, 
				.first("text_conv").as("text_conv").last("number").as("number")  //text는 처음 등록한 것만 가져오고, number는 나중에 등록한 것만 가져온다.
		);
		results = template.aggregate(agg, "body", HashMap.class);
		if(results != null){
			List<HashMap> target = results.getMappedResults();
			target.forEach(System.out::println);
		}
	}

처음값(text_conv)과 마지막값(number)만 나온다.

 

5. 문자열 및 날짜에 대한 처리 기능이다. substring을 활용해 문자열을 줄일 수 있고, dateAsFormattedString을 통해 날짜형태를 YYYYMMDD 등으로 원하는 방법데로 바꿀 수 있다.

	public void simpleSubStringDateToString(){
		Aggregation agg = null;
		AggregationResults<HashMap> results = null;
		agg = Aggregation.newAggregation(
			Aggregation.project()  //1. 매핑할 이름
				.and("1").as("1")  
				.and("text").substring(0,2).as("text_conv")  //2. 문자열 자르기 substring
				.and("type").as("type")
				.and("date").dateAsFormattedString("%Y-%d-%m").as("conv_date")  //날짜파싱
				.and("number").as("number"),
			Aggregation.match(     //3. 조건 null이 아닌것 
				new Criteria().andOperator(
						Criteria.where("text_conv").regex("")  //텍스트 전부 조건
					)
			),
			Aggregation.group("type","conv_date", "text_conv").count().as("count")
		);
		results = template.aggregate(agg, "body", HashMap.class);
		if(results != null){
			List<HashMap> target = results.getMappedResults();
			target.forEach(System.out::println);
		}
	}

날짜 형식(yyyymmdd) 변경, 텍스트는 substring으로 가공하기

 

6. body 컬렉션과 head 컬렉션을 합쳐서(join) 결과를 나타낸다. 서로 가지고 있는 type이라는 도큐먼트 속성을 참조키로 사용한다. LookupOperation클래스를 여러개 활용해서 여러 항목을 묶을 수 있다. 여기서는 1개이다.

	public void simpleLookUp(){
		Aggregation agg = null;
		AggregationResults<HashMap> results = null;
		
		LookupOperation lookUp = LookupOperation.newLookup()
				.from("head").localField("type")   //1. 묶을 컬렉션 이름은 head, 대상 도큐먼트는 같은 이름인 type
				.foreignField("type").as("ref");  //2. 조회할 컬렉션에서 해당 head 컬렉션이 묶일 도큐먼트 이름은 type, 별명은 ref
		agg = Aggregation.newAggregation(
			lookUp,  //3. Join 개념
			Aggregation.project()  //4. 매핑
				.and("type").as("type")
				.and("ref").as("ref")  
				.and("text").as("text"),
			Aggregation.match(    
				new Criteria().andOperator(
						Criteria.where("text").regex("")  //5. 텍스트 전부 조건
					)
			),
			Aggregation.group("type", "ref")
		);
		results = template.aggregate(agg, "body", HashMap.class);
		if(results != null){
			List<HashMap> target = results.getMappedResults();
			target.forEach(System.out::println);
		}
	}

ref에는 참조하는 대상을 전부 묶어서 배열로 가져온다. 1개만 있으면 0번 배열 1개만 나온다.

 

7. body 컬렉션과 head 컬렉션을 합치는데 원하는 특정 1개의 조건의 필드만 가져오게 한다. Projection부분이 핵심이다. arrayElementAt 메소드의 인자값은 배열의 순서이며 0,1,2,3...순서로 증가하고 -1은 끝 값을 의미한다.

	public void simpleLookUp2(){
		Aggregation agg = null;
		AggregationResults<HashMap> results = null;
		
		LookupOperation lookUp = LookupOperation.newLookup()
				.from("head").localField("type")   //1. 묶을 컬렉션 이름은 head, 대상 도큐먼트는 같은 이름인 type
				.foreignField("type").as("ref");  //2. 조회할 컬렉션에서 해당 head 컬렉션이 묶일 도큐먼트 이름은 type, 별명은 ref
		agg = Aggregation.newAggregation(
			lookUp,  //3. Join 개념
			Aggregation.project()  //4. 매핑
				.and("type").as("type")
				.and("ref").arrayElementAt(-1).as("ref1")  //5. 참조 컬랙션 가장 마지막 가져오기
				.and("ref").arrayElementAt(0).as("ref2")  //6. 참조 컬랙션 가장 처음 가져오기
				.and("text").as("text"),
			Aggregation.match(    
				new Criteria().andOperator(
						Criteria.where("text").regex("")  //7. 텍스트 전부 조건
					)
			),
			Aggregation.group("type", "ref1", "ref2")
		);
		results = template.aggregate(agg, "body", HashMap.class);
		if(results != null){
			List<HashMap> target = results.getMappedResults();
			target.forEach(System.out::println);
		}
	}

배열형태가 아닌 Map형태로 담기게 된다.

 

8. 행으로된 내용을 1개의 대상으로 배열형태로 묶어준다. 특정 도큐먼트를 풀어서 조건에 맞게 그룹화 된 데이터에 배열형태로 들어가게 된다. UnwindOperation 클래스가 해당 역할을 해 준다.

	public void simpleUnwind(){
		Aggregation agg = null;
		AggregationResults<HashMap> results = null;

		UnwindOperation unwind = Aggregation.unwind("text");  //1.행으로 이루어진 대상을 1개의 열로 배열 형태로 풀 도큐먼트
		agg = Aggregation.newAggregation(
			unwind,
			Aggregation.project()  //2. 매핑
				.and("type").as("type")
				.and("1").as("1") 
				.and("text").as("text"),
			Aggregation.match(    
				new Criteria().andOperator(
						Criteria.where("text").regex("")  //3. 텍스트 전부 조건
					)
			),
			Aggregation.group("type", "1").push("text").as("text")  //4. push를 활용한 배열로 만든 text필드값 넣어주기
		);
		results = template.aggregate(agg, "body", HashMap.class);
		if(results != null){
			List<HashMap> target = results.getMappedResults();
			target.forEach(System.out::println);
		}
	}

push를 통해 넣어준다.

 

* 이상 자주사용되는 집계함수의 내용이다.

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글