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

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

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


몽고DB/Java 몽고DB

Mongodb Aggregate 밀리세컨드(milliseconds) 변환(날짜, 문자형식) with Mongotemplate

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2021. 7. 7.

몽고DB에 저장되어 있는 밀리세컨드(millisecond)값을 집계함수(aggregate)를 통해서 변환하는 방법 입니다.

* 기본적으로 몽고DB와 연동하는 라이브러리는 너무 낮지 않아야 합니다. : )

 

먼저 파싱 할 데이터를 살펴보겠습니다.

val 이라는 필드에 밀리세컨드 값이 들어가 있습니다.

 

val이라는 키에 밀리세컨드값이 들어가 있습니다.

해당 값을 바꾸기 위해서 ConvertOperators 클래스를 활용하여 데이터를 변환하여 줍니다.

{
    ToDate td = ConvertOperators.valueOf("val").convertToDate();  //ToDate라는 클래스가 반환 됩니다.
}

 

convertToDate메소드를 사용하면 ToDate라는 클래스 값을 받을 수 있습니다.

ToDate라는 클래스는 AbstractAggregationExpression 추상 클래스를 상속받고 있으며 해당 값은 몽고db의 질의를 위한 공통으로 사용되는 기능 입니다.

그러므로 해당 ToDate값은 몽고db에서의 project절에 사용을 할 수 있습니다.

이를 이제 한번 질의문에 적용하여 봅니다.

{
    ToDate td = ConvertOperators.valueOf("val").convertToDate();  //ToDate라는 클래스가 반환 됩니다.

    ProjectionOperation projection = Aggregation.project()  //대상 매핑
        .and("val").as("origin")
        .and(td).as("parseToDate")
        .and("1").as("1") ;
    GroupOperation groupBy = Aggregation.group("1", "origin").first("parseToDate").as("parseToDate");
    Aggregation agg = Aggregation.newAggregation( projection, groupBy );
}

 

val이라는 숫자 값을 날짜로 치환하여 parseToDate라는 이름으로 매핑하였습니다.

이를 실행하여 본 결과 입니다.

숫자값이 날짜로 변환되었습니다!!!

 

이를 조금만 응용하면 날짜값을 문자형태로("yyyy-mm-dd")도 쉽게 변환 할 수 있습니다.

처음 밀리세컨드 값을 변환하기 위해 ConvertOperators 클래스에서 valueOf 메소드를 통하여 이루어 졌다면, 날짜 값을 변환하기 위해서 Convert라는 이름을 Date로 바꾸어 DateOperators클래스를 활용하면 가능 합니다.

{
    ToDate td = ConvertOperators.valueOf("val").convertToDate();  //ToDate라는 클래스가 반환 됩니다.

    ProjectionOperation projection = Aggregation.project()  //대상 매핑
        .and("val").as("origin")
        .and(td).as("parseToDate")
        .and(DateOperators.DateToString.dateOf(td).toString("%Y-%m-%d")).as("parseToDateToString")
        .and("1").as("1") ;
    GroupOperation groupBy = Aggregation.group("1", "origin").first("parseToDate").as("parseToDate").first("parseToDateToString").as("parseToDateToString");
		
    Aggregation agg = Aggregation.newAggregation( projection, groupBy );
}

 

이를 실행하여 보면 변환된 날짜값을 문자로 바꾸는 것을 볼 수 있습니다.

밀리세컨드가 날짜로 되었다가 문자형태로 된 것을 볼 수 있습니다.

 

집계(aggregate)를 동작해야되는 필드가 이미 날짜형식의 데이터라면 간단하게 dateAsFormattedString 메소드를 활용하여 문자로 변환 할 수 있습니다.

하지만 여기서는 밀리세컨드에서 날짜로 변환된 데이터에 대해 다시 문자형식으로 변환을 하는 것 이므로 DateOperators를 활용하여 변환을 하여야 합니다.

아래 사진처럼 dateAsFormattedString 메소드를 바로 호출하여 조회해서는 안됩니다.

Projection 필드 이름이 없다는 오류를 반환하게 됩니다.

 

위 내용에 대한 최종 소스코드 입니다.

import java.util.List;

import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.ConvertOperators;
import org.springframework.data.mongodb.core.aggregation.ConvertOperators.ToDate;
import org.springframework.data.mongodb.core.aggregation.DateOperators;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;

import com.mongodb.client.MongoClient;

public class MongoDBOperatorTest {

    public static void test() {
		
        ToDate td = ConvertOperators.valueOf("val").convertToDate();  //ToDate라는 클래스가 반환 됩니다.
		
        ProjectionOperation projection = Aggregation.project()  //대상 매핑
            .and("val").as("origin")
            .and(td).as("parseToDate")
            .and(DateOperators.DateToString.dateOf(td).toString("%Y-%m-%d")).as("parseToDateToString")
            .and("1").as("1") ;
		
        GroupOperation groupBy = Aggregation.group("1", "origin").first("parseToDate").as("parseToDate").first("parseToDateToString").as("parseToDateToString");
		
        AggregationOptions option = AggregationOptions.builder().allowDiskUse(true).build();
        Aggregation agg = Aggregation.newAggregation( projection,	groupBy ).withOptions(option);
		
        AggregationResults<Document> results = template.aggregate(agg, "testCollection", Document.class);
		
        List<Document> list = results.getMappedResults();	
        list.forEach(System.out::println);
    }
}

 

물론 변환된 필드인 parseToDateToString값과 parseToDate값에 대해서도 group을 통해서 집계 할 수 있습니다.

위 내용 이외의 StringOperators, ArrayOperators 등등 다양한 쿼리 연산자 클래스를 통해서 데이터를 유용하게 다룰수가 있습니다.

 

* 추가 ------

밀리세컨드 값을 날짜 형식으로 변환하면 기본 설정인 UTC타입의 값으로 변환이 되어 버립니다.   * TimeZone.none()

UTC형식으로 변환되어도 상관 없다면 문제되는 것은 없지만, 만약 한국시간대로(GMT) 변환을 해야되는 경우라면  시간차이가 9시간 나므로 값의 범위가 달라질 수 있습니다.

아래와 같은 예로,

2021년 7월 1일 데이터가 20개 나와야 하는데 그렇지 않고 7월 1일 10개, 6월 30일 10개 이런식으로 나올 수 있습니다.

그러므로 TimeZone 설정을 통하여 한국 시간과 맞게 나오도록 해야 합니다.

import org.springframework.data.mongodb.core.aggregation.ConvertOperators.ToDate;
import org.springframework.data.mongodb.core.aggregation.DateOperators;
import org.springframework.data.mongodb.core.aggregation.DateOperators.Timezone;

public class TestClass{
    public void test{
        //생략..
        ToDate td = ConvertOperators.valueOf("대상날짜").convertToDate();
        Timezone zone = DateOperators.Timezone.valueOf("Asia/Seoul");
        ProjectionOperation projection = Aggregation.project()  //대상 매핑
        .and("대상날짜").as("origin")
        .and(td).as("parseToDate")
        .and(DateOperators.dateOf(td).withTimezone(zone).toString("%Y-%m")).as("parseToDateToString")
        .and("1").as("1") ;
        //생략..    
    }
}

 

DateOperators클래스에 withTimeZone 메소드를 호출한 다음에 필요한 값인 TimeZone 을 넣어주면 한국시간에 맞는 데이터로 변환되는 것을 볼 수 있습니다.

물론 해당 값을 바꾸면 원하는 국가별 시간대로 변경 가능 합니다.

아래 사이트는 Zone코드가 나온 사이트 입니다.

https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

 

이상으로 몽고db에서 밀리세컨드(milliseconds)값을 날짜 또는 문자형식으로 변환하는 집계(Aggregate)동작 방법에 대해서 살펴 보았습니다.

궁금한점 또는 틀린 부분은 언제든 연락주세요. 👻

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

댓글