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

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

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


몽고DB/Java 몽고DB

Watch 함수를 통한 몽고DB 트리거 만들기(mongoDB watch trigger)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2022. 1. 28.

 

몽고DB에서 제공하는 watch 함수를 사용하면 트리거를 만들 수 있습니다.

몽고DB는 트리거(trigger)를 제공하지 않기 때문에 관계형 데이터베이스처럼 데이터의 변화에 따른 행동을 정의하기가 다소 불편했던 것은 사실 입니다

 * 2022년 1월 기준

 

몽고db에서는 컬렉션 객체에서 watch 함수를 지원 합니다.

https://docs.mongodb.com/manual/reference/method/db.collection.watch/

 

db.collection.watch() — MongoDB Manual

Docs Home → MongoDB Manualdb.collection.watch( pipeline, options )mongosh MethodThis is a mongosh method. This is not the documentation for Node.js or other programming language specific driver methods.In most cases, mongosh methods work the same way as

docs.mongodb.com

 

watch 함수는 바라보고 있는 컬렉션에 대한 변화를 감지하여 정의해 둔 콜백함수에 내용을 전달하게 되어 있습니다. 

마찬가지로 Java에서 주로 사용되는 Mongotemplate를 사용하면 쉽게 watch메소드(함수)를 사용할 수 있습니다.

 

먼저 Mongotemplate 객체에서 컬렉션 값을 가져 옵니다.

import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;

public class 몽고DB_WATCH_TEST {
    public MongoTemplate template;

    public void test(){
        MongoCollection<Document>  collection = template.getCollection("바라볼컬렉션");
    }

}

 

가져온 컬렉션 값에서 watch 메소드를 호출합니다.

watch 메소드는 Iterable 인터페이스를 상속 받고 있습니다. 

그러므로 해당 메소드에서 hasNextnext 메소드를 호출하여 반복문을 돌려 줍니다.

그러면 ChangeStreamDocument 라는 클래스를 만날 수 있습니다.

해당 클래스에는 바라보는 컬렉션의 변화된 내용이 담겨 있습니다.

import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.changestream.ChangeStreamDocument;

public class 몽고DB_WATCH_TEST {
    public MongoTemplate template;

    public void test(){
        MongoCollection<Document>  collection = template.getCollection("바라볼컬렉션");
        MongoCursor<ChangeStreamDocument<Document>> cursor = collection.watch().iterator();	
        while(cursor.hasNext()) {
            ChangeStreamDocument<Document> item = cursor.next();
        }
    }

}

 

그런데 해당 기능에서의 조금 아쉬운 점은 발행(publish)과 구독(subscribe) 형태의 기능으로 개발되어 있지 않기 때문에 반복문인 while 명령어를 실행하면 thread 전체가 멈춘다는 것 입니다.

그러므로 별도의 스레드(thread)를 만들어서 실행하여 줍니다.

이때 대표적인 값 2개를 출력하여 보겠습니다.

import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.changestream.ChangeStreamDocument;

public class 몽고DB_WATCH_TEST {
    public MongoTemplate template;

    public void test(){
        MongoCollection<Document>  collection = template.getCollection("바라볼컬렉션");
        MongoCursor<ChangeStreamDocument<Document>> cursor = collection.watch().iterator();	
        new Thread(()->{
            while(cursor.hasNext()) {
                ChangeStreamDocument<Document> item = cursor.next();
                System.out.println(item.getFullDocument());  //변화된 도큐먼트 전체 값들
                System.out.println(item.getOperationType()); //변화된 타입
                System.out.println("");
            }
        }).start();
    }

}

 

요렇게 하고나면 이제 등록, 수정, 삭제를 한번 해 보겠습니다.

import org.bson.Document;

import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.MongoTemplate;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.changestream.ChangeStreamDocument;

public class 몽고DB_WATCH_TEST {
    public MongoTemplate template;
    private static final String 바라볼컬렉션 = "targetCollection";

    public void test(){
        MongoCollection<Document>  collection = template.getCollection(바라볼컬렉션);
        MongoCursor<ChangeStreamDocument<Document>> cursor = collection.watch().iterator();	
        new Thread(()->{
            while(cursor.hasNext()) {
                ChangeStreamDocument<Document> item = cursor.next();
                System.out.println("등록시 : "+item.getFullDocument());
                System.out.println("수정시 : "+item.getUpdateDescription());
                System.out.println("아이디 : "+item.getDocumentKey());
                System.out.println("작업형태 : "+item.getOperationType());
                System.out.println("");
            }
        }).start();
        
        //#0. 위 watch 함수가 정상적으로 동작하기 위해 잠시 1초간 멈춤니다
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
		
        //#1. 등록
        Document doc = new Document();	
        doc.put("text", "hello world");
        doc.put("number", 5678);
        template.insert(doc, 바라볼컬렉션);	
		
        //#2. 수정
        Query query = new Query();
        query.addCriteria(Criteria.where("number").is(5678));
        Update update = new Update();
        update.set("test", "change");
        template.updateFirst(query, update, 바라볼컬렉션);
		
        //#3. 삭제
        template.remove(query , 바라볼컬렉션);
    }

}

 

등록, 수정, 삭제 행동을 달아보았습니다.

해당 클래스를 실행하면 아래와 같은 결과가 나옵니다.

오호..잘나옵니다!

 

getOperationType메소드를 활용하면 등록을 하는경우에  insert가 나오고, 수정하면 update, 삭제하면 delete 값이 나오는 것을 볼 수 있습니다.

여기에 사용자가 원하는 기능을 붙이면 훌륭한 트리거 기능이 완성 됩니다. 

일반적으로 JPA 기능을 사용하는 분 들 이라면..사실 이러한 세부적 기능을 만들기가 쉽지가 않습니다.

구글링을 하여도 관련된 글을 찾기가 무척 어려웠던거 같습니다. -_ㅜ

 

이상으로 Watch 함수를 통한 몽고DB 트리거(mongoDB watch trigger)에 대해서 살펴보았습니다.

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

 

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

댓글