몽고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 인터페이스를 상속 받고 있습니다.
그러므로 해당 메소드에서 hasNext와 next 메소드를 호출하여 반복문을 돌려 줍니다.
그러면 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)에 대해서 살펴보았습니다.
궁금한점 또는 틀린 부분은 언제든 연락주세요!👻
댓글