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

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

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


몽고DB/Java 몽고DB

Mongotemplate에서 배열값 관리 (Mongotemplate push, pull)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2020. 5. 13.

 

* Mongotemplate Array, Mongotemplate 배열

 

몽고DB에서 데이터는 다양한 형태로 존재 합니다.

문자, 숫자, 배열, Json형태 등등 여러 형태가 자유롭게 존재합니다.

일반적으로 update라는 메소드를 통해서 몽고DB의 데이터를 변경 할 수 있습니다.

 

그런데, 만약에 내가 수정해야되는 데이터가 배열형태면 어떻게 해야 될 까요?

배열형태에 특정 데이터를 삭제하거나, 추가하려면 어떻게 해야 되는 것 일까요?

 

일반적인 방법은 해당 내용을 조회하여 배열 데이터를 가져온 뒤에 배열에서 필요한 내용을 제거하거나 추가한 뒤에 업데이트를 하곤 합니다.

아래 예를들어 보겠습니다.

private MongoTemplate template;

private void selectAndUpdate(){
    Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb488f5afd05505a84976b")) );
    Document doc = template.findOne(query, Document.class, "컬렉션");  //데이터를 가져와서  

    List<String> list = doc.getList("list", String.class);  //list라는 필드에서 값을 가져와
    list = list.stream().filter( (arg)->{  //이런식으로 데이터를 재 조립한뒤에
        return true; 
    }).collect(Collectors.toList());
    
    Update update = new Update();
    update.set("list",list);
    template.updateFirst(query, update, "컬렉션");  //다시 업데이트 해 줍니다.
}

 

위 소스코드는 간단한 예제 입니다. 이를 단계별로 설명 해 보면,

 1. 컬렉션에서 특정 데이터를 가져옵니다.

 2. 컬렉션에서 가져온 데이터에서 배열값을 가져옵니다.

 3. 배열값에 필요한 내용을 변경합니다.

 4. Update객체를 가져옵니다.

 5. 내가 바꿀 데이터를 넣어줍니다.

 6. 데이터를 업데이트합니다.

 

총 6단계별로 진행이되며 조회를 한 뒤에 수정행위를 해야되는, 데이터베이스에 2번이나 접속해야되는 부분이 존재 하였습니다.

만약 배열 값이 몇 천개, 몇 만개이상의 대량의 데이터가 존재한다면 시스템상 과부하가 올 수도 있을 것 입니다.

 

조금 더 효과적으로 할 수 있는 방법으로 Mongotemplate에서 push와 pull 이라는 기능을 사용하면 됩니다!

push와 pull은 사실 Mongotemplate가 지원하는 기능이 아니라 몽고DB가 지원하는 기능입니다.

우리에게 중요한 사실은 push와 pull을 사용하면 데이터베이스에 2번접속하거나 자바의 Collection을 굳이 사용하지 않아도 된 다는 점 입니다.

배열 값에 대해서 추가를 하려면 push를 사용하고, 배열 값에 대해서 제거를 하려면 pull을 사용 합니다.

 

1. key와 value 가 존재하는 배열에서의 데이터 관리 방법

아래 사진처럼 데이터가 존재한다고 합니다.

배열 형태가 키&값 형태로 되어 있습니다.

 

해당 배열은 키와, 값으로 구분되어지는 배열입니다.

여기서 배열 이름은 list입니다.

이곳에 데이터를 추가하는 메소드를 만들어 보겠습니다.

private void pushData(MongoTemplate template){
    Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb768b51bc8e05d8760999")) );
    Update update = new Update();
    
    List<Document> array = new ArrayList<>();  //데이터를 추가할 배열 입니다.
    
    Document item = new Document();  //배열안에 담을 값 입니다.
    item.put("address", "new address");
    item.put("value", "new data");
    array.add(item);
    
    item = new Document();
    item.put("address", "new address2");
    item.put("value", "new data2");
    item.put("new_number", 1234);
    array.add(item);
    
    update.push("list").each(array);  //push라는 메소드에 키 값을 넣어주고 each를 통해서 해당 배열에 순차적으로 저장하게 하였습니다.
    template.updateFirst(query, update, "컬렉션");
}

 

어렵지 않는 코드입니다.

여기서의 핵심은 Update 클래스에서 제공하는 push메소드 입니다.

push 메소드에 배열의 키 값을 넣어주고, each라는 메소드를 통해서 해당 데이터가 순차적으로 저장되게 하면 됩니다.

그렇게하고 난 뒤에 실행하여보면 데이터가 올바르게 추가 된 것을 볼 수 있습니다.

데이터가 추가되었습니다.

 

여기에 "address" 값이 "new address" 인 데이터를 제거 해 보도록 하겠습니다.

배열에서의 데이터 제거는 pull이라는 메소드를 사용 합니다.

private void pullData(MongoTemplate template){
    Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb768b51bc8e05d8760999")) );
    Update update = new Update();
    update.pull("list", new BasicDBObject("address", "new address"));
    template.updateFirst(query, update, "컬렉션");
}

 

Update 클래스에서 pull이라는 메소드를 호출합니다.

pull메소드에서 첫번째 값으로 제거할 배열 이름을 입력합니다.

그리고 BasicDBObject 클래스를 통해서 제거할 대상의 데이터를 입력하여줍니다.

address값이 new address인 배열이 제거 되었습니다.

 

 

2. 1차원 배열에서의 데이터 관리 방법

배열의 값이 1차원 배열처럼 단순한 경우 작업은 더욱 쉽습니다.

아래 사진처럼 데이터가 존재 합니다.

단순한 배열 입니다.

 

데이터를 넣는 메소드는 push 이며, 데이터를 제거하는 메소드는 pull입니다.

내용이 쉬워서 메소드를 1곳에서 합쳐보았습니다.

private void pullAndPushSimple(MongoTemplate template){
    Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb789adb679513abec77e3")) );
    Update update = new Update();
    
    //데이터를 제거 합니다.
    update.pull("list", "b");  //배열값이 b인 데이터를 제거합니다.
    template.updateFirst(query, update, "컬렉션");
    
    //데이터를 추가 합니다.
    String [] newItem = new String[]{"abcd","efg"};
    update = new Update();
    update.push("list").each(newItem);
    template.updateFirst(query, update, "test_array");    
}

 

each도 어렵지 않으며, push도 어렵지 않습니다.

해당 메소드를 실행하면 정상적으로 데이터가 변경된 것을 볼 수 있습니다.

b가 제거되면서 2개의 값이 추가 되었습니다.

 

3. 2차원 배열에서의 데이터 관리 방법

배열의 값이 2차원 배열처럼 단순한 경우 push는 동일하게 사용 해 주면 됩니다.

그러나 pull에서의 사용 방법은 조금 다릅니다.

push하는 방법을 생략하고 pull하는 방법에 대해서 바로 넘어가겠습니다.

먼저 아래처럼 데이터가 존재한다고 합니다.

 

해당 배열에서 1번째 배열의 c값만 지우는 경우와 배열 인덱스 2번째를 지우는 방법에 대해서 알아보겠습니다.

아래 소스코드를 확인하여 주세요.

private void pullData3(MongoTemplate template){
    Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb7a55f6ddee66bf768d7f")) );
    Update update = new Update();

    update.pull("list.$[]", "c");  //2중 배열에서의 특정 값만 지우는 방법
    template.updateFirst(query, update, "컬렉션");

    update = new Update();
    update.pull("list", new String []{"e","f"});  //2중 배열에서의 1개 전체를 지우는 방법
    template.updateFirst(query, update, "컬렉션");
}

 

표현하는 방식에 차이가 존재하였습니다.

2중배열에서의 내부 값을 참조하기 위해서 .$[] 라는 표현식이 사용 되었습니다.

해당 표현식은 몽고DB에서 정의한 표현식 입니다.

* 참고

www.docs.mongodb.com/manual/reference/operator/update-array/

 

첫번째 update는 c값을 가진 배열의 한 부분만 제거하는 업데이트입니다.

그리고 두번째 업데이트는 e와 f값을 가지고 있는 배열을 제거하는 업데이트입니다.

값이 제거 되었습니다.

 

업데이트 하는 곳 에서 new 를 통해서 새로이 객체를 생성 해 준 것은 list에 대한 update문이 표현식이 다른 상태에서 실행하게되면 오류가 발생하기 때문 입니다.

* 한꺼번에 업데이트 해 보시면 어떤의미인지 알 수 있습니다. ^^

 

여기까지 Mongotemplate에서 배열에 대해 데이터를 관리하는 방법에 대해서 살펴보았습니다.

여기서의 핵심은 Mongotemplate를 활용하여 배열 데이터를 손쉽게 관리하려 한다면,

단순한 배열의 모양 보다는 key와 value가 존재하는 배열 형태가 훨씬 편리하고 관리하기 쉽다는 점 입니다.

 

위 내용에 사용된 최종 소스코드입니다.

import java.util.ArrayList;
import java.util.List;

import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.MongoTemplate;
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 com.mongodb.BasicDBObject;


public class SampleMongoDB{
    
    private MongoTemplate template;
    
    //구 방식의 수정 예제입니다. 데이터베이스에 2번이나 접속 해야 되는 방식 입니다.
    private void selectAndUpdate(){
        Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb488f5afd05505a84976b")) );
        Document doc = template.findOne(query, Document.class, "컬렉션");  //데이터를 가져와서  
    
        List<String> list = doc.getList("list", String.class);  //list라는 필드에서 값을 가져와
        list = list.stream().filter( (arg)->{  //이런식으로 데이터를 재 조립한뒤에
            return true; 
        }).collect(Collectors.toList());
        
        Update update = new Update();
        update.set("list",list);
        template.updateFirst(query, update, "컬렉션");  //다시 업데이트 해 줍니다.
    }
    
    //push에 업데이트할 대상을, each에 집어넣을 데이터를 입력합니다.
    private void pushData(MongoTemplate template){
        Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb768b51bc8e05d8760999")) );
        Update update = new Update();
        
        List<Document> array = new ArrayList<>();  //데이터를 추가할 배열 입니다.
        
        Document item = new Document();  //배열안에 담을 값 입니다.
        item.put("address", "new address");
        item.put("value", "new data");
        array.add(item);
        
        item = new Document();
        item.put("address", "new address2");
        item.put("value", "new data2");
        item.put("new_number", 1234);
        array.add(item);
        
        update.push("list").each(array);  //push라는 메소드에 키 값을 넣어주고 each를 통해서 해당 배열에 순차적으로 저장하게 하였습니다.
        template.updateFirst(query, update, "컬렉션");
    }
    
    //BasicDBObject 클래스를 통해서 삭제할 대상의 키와 값을 넣어줍니다.
    private void pullData(MongoTemplate template){
        Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb768b51bc8e05d8760999")) );
        Update update = new Update();
        update.pull("list", new BasicDBObject("address", "new address"));
        template.updateFirst(query, update, "컬렉션");
    }
    
    //단순 1차원 배열에 사용하는 예문입니다.
    private void pullAndPushSimple(MongoTemplate template){
        Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb789adb679513abec77e3")) );
        Update update = new Update();
        
        //데이터를 제거 합니다.
        update.pull("list", "b");  //배열값이 b인 데이터를 제거합니다.
        template.updateFirst(query, update, "컬렉션");
        
        //데이터를 추가 합니다.
        String [] newItem = new String[]{"abcd","efg"};
        update = new Update();
        update.push("list").each(newItem);
        template.updateFirst(query, update, "test_array");    
    }
    
    //단순 2차원 배열에서 사용하는 예문 입니다.
    private void pullData3(MongoTemplate template){
        Query query = new Query().addCriteria(Criteria.where( "_id" ).is( new ObjectId("5ebb7a55f6ddee66bf768d7f")) );
        Update update = new Update();
    
        update.pull("list.$[]", "c");  //2중 배열에서의 특정 값만 지우는 방법
        template.updateFirst(query, update, "컬렉션");
    
        update = new Update();
        update.pull("list", new String []{"e","f"});  //2중 배열에서의 1개 전체를 지우는 방법
        template.updateFirst(query, update, "컬렉션");
    }
    
}

 

가급적이면 key와 value의 형태로 배열데이터를 사용하여 좀 더 관리하기 쉽도록 하였으면 좋겠습니다!

* 각종 문의사항 있으시면 댓글 또는 메일로 연락주세요!

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

댓글