본문 바로가기
컴퓨터/NoSQL 데이터베이스

[DB] 몽고DB 배열 필드를 다뤄보자/MongoDb Array field

by 도도새 도 2023. 5. 1.

몽고 DB 배열

 

프로젝트를 하던 중 배열을 몽고DB의 배열로된 필드를 본격적으로 다뤄야 할 일이 생겼다. 이에 앞서 몽고 DB에서 배열을 다루는 다양한 방법을 정리한다.

 

 

몽고 DBJSON(저장은 BSON) 형식으로 다룰 수 있기 때문에 배열과 관련된 연산을 지원한다. 이번에 몽고DB의 배열과 관련된 연산을 정리한다.

 

예시와 함께 보기 위해 우선 아래 명령어를 입력하여 도큐먼트를 생성한다.

 

db .employee .insertOne ({

   name :"departments"

})

 

배열 쿼리 연산자

 

$push

 

$push는 배열이 이미 존재하면 배열의 끝에 요소를 추가한다. 다른 연산들이 그렇듯 push 또한 존재하지 않으면 새로운 배열을 생성한다. 추후 설명할 $each를 사용하면 여러값을 필드에 삽입할 수 있지만, 그렇지 않을 경우 하나의 값만 삽입 가능하다.

db .employee .updateOne ({name :"departments"}, {$push :{department :"IT"}})

IT를 삽입하였다.

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT" ] }

두 번 사용하면?

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT", "IT" ] }

 

department 필드의 배열에 IT가 두 번 들어간 것을 확인 할 수 있다.

$position을 사용하면 특정 위치에 삽입을 할 수 있다. $each와 함께 사용한다. 이에 대한 예시는 아래 $each에서 기술한다.

 

$addToSet

 

배열에 값이 없을 때만 값을 추가한다.

 

db .employee .updateOne ({name :"departments"}, {$addToSet :{department :"Accounting"}})

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT", "IT", "Accounting" ] }

두 번 사용하면?

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT", "IT", "Accounting" ] }

새로운 값이 추가되지 않음을 확인할 수 있다.

 

$pop

 

배열의 첫 번째나 마지막 값을 제거한다. 큐나 스택에서 처음이나 마지막 요소만 뺄 수 있는 것을 생각하면 되겠다.

1은 마지막 요소, 1은 첫 요소를 삭제한다.

db .employee .updateOne ({name :"departments"}, {$pop :{department :1 }});

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT", "IT" ] }

 

$pull

 

배열에서 값이 일치하는 요소를 제거한다.

 

db .employee .updateOne ({name :"departments"}, {$pull :{department :"IT"}});

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ ] }

 

$pullAll

 

배열에서 값이 일치하는 모든 요소를 제거한다.

 

$each

 

$push$addToSet 메소드들과 함께 사용하여 배열에 여러 값을 추가할 때 사용한다.

 

db .employee .updateOne ({name :"departments"}, {$push :{department :{$each :["IT", "CS", "HR"]}}})

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT", "CS", "HR" ] }

 

앞서 $push에서 설명한 $position 사용법은 아래와 같다.

 

db .employee .updateOne ({name :"departments"}, {$push :{department :{$each :["using position"], $position :1 }}})

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "No IT", "using position", "CS", "HR" ] }

 

$elemMatch

 

배열에서 일치하는 요소를 선택한다.

 

이를 확인하기 위해 아래와 같이 작성한다.

db .employee .insertOne ({

   name :"depart2",

   departments :[

     {name :"HR"},

     {name :"IT"}

   ]

})

 

출력값

{ "_id" : ObjectId("644ea836f3516b617492ea1c"), "name" : "depart2", "departments" : [ { "name" : "HR" }, { "name" : "IT" } ] } //임베디드 서브어레이의 형태이다. 객체 배열이라는 의미.

 

db .employee .find ({departments :{ $elemMatch :{name :"IT"}}})

 

여기서 eleMatch를 사용하면 해당하는 값을 얻을 수 있다. 즉 배열 내부의 각 요소가 입력값과 일치하는지 여부를 확인한다.

 

출력값

{ "_id" : ObjectId("644ea836f3516b617492ea1c"), "name" : "depart2", "departments" : [ { "name" : "HR" }, { "name" : "IT" } ] }

 

객체 배열내의 값이 아니라 그저 배열 내의 값중 입력값과 일치하는 것을 찾으려면 그저 아래와 같이 사용하면 된다.

 

db .collection .find ({ department :"IT" })

 

출력값

{ "_id" : ObjectId("6447f2d5b1e44249bd4e6150"), "name" : "minjeong", "age" : 21, "department" : "IT" }

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "IT", "CS", "HR" ] }

즉 값이 배열 내에 있어도 정상적으로 출력해준다.

 

$slice

 

배열의 일부분을 선택한다. 파이썬에서 지원하는 슬라이스와 유사하다.

따라서 1을 마지막 요소를 의미, -2는 마지막에서 2번째를 의미 한다.

 

$sort

 

배열을 정렬한다.

 

 

+ dot notation

 

.을 사용하면 배열의 n번쨰 요소를 선택할 수 있다. 이를테면 0번째 요소 값을 바꾸려면?

 

db .employee .updateOne ({name :"departments"}, {$set :{"department.0":"No IT"}})

 

출력값

{ "_id" : ObjectId("644ea0f0f3516b617492ea1a"), "name" : "departments", "department" : [ "No IT", "CS", "HR" ] }

 

결과를 보다시피 ITNo IT로 바뀌었다.

 

객체 배열도 바꿀 수 있을까?

 

db .employee .updateOne ({name :"depart2"}, {$set :{"departments.1": {  name :"new IT", and :"HEllO world" }}})

1번 인덱스의 배열 요소에 nameand를 키로 하는 필드로 하는 객체로 변경한다.

 

출력값

{ "_id" : ObjectId("644ea836f3516b617492ea1c"), "name" : "depart2", "departments" : [ { "name" : "HR" }, { "name" : "new IT", "and" : "HEllO world" } ] }

 

보다시피 정상적으로 변경되었음을 확인할 수 있다.

 

dot notation을 활용하면 각 필드 내부의 값에 쉽게 접근할 수 있다. 마치 JS의 객체와 유사하다고 볼 수 있다.

 

마지막으로 이를 이용해 위의 도큐먼트의 HELLO world BYE로 바꾸어보자.

 

db .employee .updateOne ({name :"depart2"}, {$set :{"departments.1.and":"Bye Bye"}})

 

출력값

{ "_id" : ObjectId("644ea836f3516b617492ea1c"), "name" : "depart2", "departments" : [ { "name" : "HR" }, { "name" : "new IT", "and" : "Bye Bye" } ] }

 

+ 이러한 작업은 positional operator를 사용하면 더욱 쉽다고한다. $를 사용하는데, 이는 동적으로 위치를 정해주는 역할을 한다. 쿼리 도큐먼트에 일치하는 첫 번째 위치(인덱스값)을 자동으로 할당한다.

 

즉 이런 예시가 가능하다.

 

db .employee .updateOne (

  {"departments.and":"Bye Bye" },

  { "$set": { "departments.$.and":"hey" } }

)

 

보면 쿼리 도큐먼트는 departments.and이다. departments내의 and값이 Bye Bye인 필드의 위치를 $이 담는다.

 

따라서 $set과 위에서 배열에 숫자로 접근하는 방식을 통해 Bye Bye값을 hey로 바꾼 것이다.

 

출력값

{ "_id" : ObjectId("644ea836f3516b617492ea1c"), "name" : "depart2", "departments" : [ { "name" : "HR" }, { "name" : "new IT", "and" : "hey" } ] }

 

$ 사용 몽고DB 공식 문서:

https://www.mongodb.com/docs/manual/reference/operator/update/positional/

댓글