* 에러 기록
MongoServerError: E11000 duplicate key error collection: thona.products index: _id_ dup key: { _id: 100 }
블로그 글에 따라 몽고 DB 를 연습하다가 위와 같은 오류가 나면 해당 DB (thona) 를 삭제하고, 다시 DB 를 생성하고 컬렉션을 추가하고 진행하면 된다.
* Mongo DB 설치
아래쪽 설치내용은 헷갈리므로 위의 최신 설치가이드를 참고하기 바란다.
설치시 주의사항은 환경변수 설정(윈도우 탐색기와 제어판의 시스템 환경변수 편집 이용)이 필요하다. 아래 링크를 클릭하여 설치에 참고하도록 하자! mongo shell 도 함께 다운로드하고 C 드라이브의 Program files 폴더 안으로 복사한다. 그런 다음 bin 폴더의 mongosh 를 실행하고 엔터키를 누른다.
환경변수 설정후 재부팅해줘야 제대로 설치를 인식한다.
엔터키를 누르면 아래와 같은 내용이 나온다.
https://kitty-geno.tistory.com/155
* 윈도우에서 MongoDB 서버 켜고 끄기
CMD 창을 관리자 버전으로 실행한다. net start MongoDB 를 입력하고 위와 같은 메세지가 나오면 이미 서버가 구동중이다. net stop MongoDB 를 입력하면 MongoDB 서버를 셧다운한다.
* 데이터 CRUD 연습 - 명령창(CMD) 사용
mongo client 에서 server 접속
mongo shell 은 곧 없어진다고 한다. 추후에는 mongosh 를 사용해야 하므로 아래 문서를 참고하여 mongosh 를 설치하도록 하자!
설치후 CMD 창을 관리자 권한으로 실행하고 mongosh 를 입력하면 아래와 같은 화면이 나온다.
mongosh "mongodb://localhost:27017/syleemomo" 라는 특정 몽고 DB 인스턴스에 접속한다. 나머지 명령어는 이전 몽고 쉘과 동일하다.
* 몽고 DB 설치 확인하기
mongo -version
cmd 창을 열고 위와 같이 입력한다. 현재 블로그 내용은 몽고 DB 5.0.3 버전에서 테스트하였으므로 하위버전이나 상위버전에서 일부 내용은 제대로 동작하지 않을 수 있다.
* 몽고 클라이언트로 db 서버 접속하기
mongo
cmd 창을 열고 위와 같이 입력한다.
* 몽고 DB 사용하기
show dbs - 데이터베이스(DB) 전체 목록 보기
현재까지 생성된 전체 DB 목록을 조회한다. 몽고 DB 에는 기본적으로 admin, config, local 이라는 DB 가 존재한다. DB 이름과 함께 우측에는 DB 용량도 표시되어 있다.
use [DB 이름] - 데이터베이스(DB) 생성 및 조회
해당 DB 로 이동한다. 이동하고자 하는 DB 이름이 목록에 존재하지 않으면 해당 DB 이름으로 DB 를 새로 생성하고, 해당 DB 로 이동한다. 하지만 생성한 DB는 show dbs 를 해봐도 보이지 않는다. 이유는 DB 에 컬렉션이 하나 이상 존재하고, 컬력션 안에 도큐먼트가 하나 이상 존재해야 생성한 DB 가 목록에 나타난다.
db.dropDatabase() - 데이터베이스(DB) 제거
DB 목록에서 현재 내가 위치한 곳의 DB 를 제거한다. DB 를 제거하기 전에 먼저 제거하고자 하는 DB 로 이동해야 한다. use [DB 이름] 명령어를 사용하면 된다.
db.[컬렉션 이름].insert() - 하나의 도큐먼트(document) 생성
특정 컬렉션에 도큐먼트를 추가하려면 insert 메서드를 사용하면 된다. 위에서 persons 는 컬렉션 이름이다. 컬렉션에는 insert 메서드가 존재하며 이를 이용하여 새로운 도큐먼트 객체를 추가할 수 있다. 도큐먼트를 생성할때 name, age 와 같은 필드명에는 따옴표("")를 붙여주지 않아도 제대로 생성이 된다.
db.[컬렉션 이름].insertMany() - 다수의 도큐먼트(document) 생성
컬렉션의 insertMany 메서드는 해당 컬렉션에 다수의 도큐먼트를 생성한다. 위의 명령어는 persons 컬렉션에 3개의 도큐먼트를 추가로 생성하고 있다. insertMany 의 인자는 배열처럼 대괄호([])로 묶어줘야 한다. 또한, 괄호나 대괄호를 열고 나서 닫지 않은채 엔터키를 누르면 ... 이 생기면서 여러줄에 걸쳐서 명령어를 입력할 수 있다. find 메서드로 확인해보면 도큐먼트가 제대로 생성되었는지 확인할 수 있다.
db.person.find().pretty()
컬렉션을 좀 더 읽기 쉽게 보려면 위와 같은 명령어로 사용하면 된다.
db.persons.insertOne({name: "syleemomo", age: 57, friends: ["영감", "할머니"]}
컬렉션에 위의 도큐먼트 1개를 더 추가하도록 한다.
show collections - 컬렉션(collection) 목록 조회
현재 내가 위치한 DB 의 컬렉션 목록을 보여준다. use [DB 이름] 명령어로 DB 를 변경한 다음 컬렉션 목록을 조회하면 된다. 위에서는 현재 DB 에 persons 컬렉션만 존재한다.
db.[컬렉션 이름].find() - 도큐먼트(document) 전체 목록 조회
컬렉션의 전체 도큐먼트를 조회하려면 위와 같이 find 메서드를 사용하면 된다. 현재까지 생성된 도큐먼트의 전체 목록을 화면에 보여준다. 도큐먼트 ID 값은 _id 라는 필드명으로 존재한다. 한가지 주의할 점은 컬렉션의 도큐먼트 목록을 조회하기 전에 해당 컬렉션이 존재하는 DB 로 이동해야 한다.
db.[컬렉션 이름].find({ 필드명 : VALUE })
컬렉션의 find 메서드는 검색하고자 하는 도큐먼트의 필드명과 값을 설정할 수 있다. 이렇게 하면 특정 필드의 값과 일치하는 도큐먼트를 검색할 수 있다. 관계형 데이터베이스의 where 키워드와 유사하다. 위 예시에는 persons 컬렉션에서 name 필드의 값이 문자열 syleemomo 와 일치하는 모든 도큐먼트를 검색한다. 즉, 여러개의 도큐먼트가 검색될 수 있다. 물론 콤마(,)를 이용하여 검색하고자 하는 다수의 필드명과 값을 설정할 수도 있다.
위에서는 persons 컬렉션에서 name 필드의 값이 "syleemomo"인 모든 도큐먼트를 검색(쿼리)한다.
friends 는 친구들의 목록을 가지고 있는 배열 필드이다. friends 배열에 "영감" 이 포함된 도큐먼트가 검색된다. 또한, friends 배열에 "길동"이가 포함된 도큐먼트가 검색된다.
위에서는 persons 컬렉션에서 friends 필드의 값이 ["영감", "할머니"] 인 도큐먼트를 검색한다.
위에서는 persons 컬렉션에서 friends 필드의 값이 ["영감", "할머니", "길동"] 인 도큐먼트를 검색한다. 이러한 도큐먼트는 존재하지 않으므로 아무것도 검색되지 않는다. 또한, friends 필드의 값이 ["할머니"] 인 도큐먼트를 검색해도 검색이 되지 않는다.
하지만 위와 같이 검색하면 검색이 성공한다. friends 배열에 "할머니" 라는 값이 포함되어 있으면 검색된다.
정리하면 find 메서드로 도큐먼트를 검색(쿼리)할때 friends: [] 로 설정하면 일치하는 도큐먼트만 검색하지만 { friends : 필드값 } 으로 설정하면 frineds 배열에 필드값을 원소로 가지고 있으면 검색이 된다.
쿼리 연산자의 자세한 내용은 문서를 참조하는 것이 좋다. 쿼리 연산자는 도큐먼트를 검색할때 약어를 사용하여 검색 조건을 설정한다. 쿼리연산자는 연산자(name) 앞에 달러($)로 표기해준다.
db.[컬렉션 이름].find( { 필드명 : { 쿼리 연산자 : VALUE }} )
비교쿼리
$gt 연산자 - 필드값이 조건에 주어진 값보다 큰 도큐먼트 검색하기
$lt 연산자 - 필드값이 조건에 주어진 값보다 작은 도큐먼트 검색하기
특정 필드의 값이 쿼리연산자에 의한 조건을 만족하는 모든 도큐먼트를 검색하려면 위와 같이 하면 된다. 위 명령어는 age 필드에 쿼리 연산자인 $gt (greater than) 을 설정함으로써 persons 컬렉션에서 나이가 30보다 많은 도큐먼트를 모두 검색하고 있다. 또한, $lt (less than) 을 설정함으로써 persons 컬렉션에서 나이가 30보다 적은 도큐먼트도 검색하고 있다.
$in 연산자 - 필드값이 배열에 존재하는 값 중에서 어느 하나인 도큐먼트 검색하기
$in 연산자는 필드의 값이 배열에 존재하는 값들 중 어느 하나라면 검색이 된다. 여기서는 persons 컬렉션에서 name 필드의 값이 "syleemomo"이거나 "gracia" 둘 중 어느 하나이면 검색된다. 그래서 3명의 사람이 검색된다. $in 연산자에는 반드시 배열 형태로 값을 설정해야 한다.
위에서는 persons 컬렉션에서 frineds 배열에 "철수" 나 "할머니"라는 값이 포함되어 있으면 검색이 된다.
$nin 연산자 - 필드값이 배열에 존재하는 어떤 값과도 해당이 되지 않는 도큐먼트 검색하기
$nin 연산자는 필드의 값이 배열에 존재하는 어떤 값과도 해당이 되지 않으면 검색이 된다. 여기서는 persons 컬렉션에서 name 필드의 값이 "syleemomo" 와 "gracia" 를 제외한 모든 도큐먼트가 검색된다. 그래서 2명의 사람이 검색된다. $nin 연산자에는 반드시 배열 형태로 값을 설정해야 한다.
논리쿼리
$and 연산자 - 서로 다른 필드조건을 동시에 만족하는 도큐먼트 검색하기
$and 연산자는 여러개의 필드 조건을 모두 만족하는 도큐먼트를 검색한다. 위에서는 persons 컬렉션에서 name 필드값이 "syleemomo" 이고, friends 필드값이 "길동"이를 포함하는 모든 도큐먼트를 검색한다. $and 연산자는 필드조건을 중괄호({})로 감싸고, 배열 형태로 조건을 추가하면 된다.
age 조건을 하나 더 추가되면 더이상 검색되는 도큐먼트가 없다.
$or 연산자 - 서로 다른 필드조건 중 어느 하나라도 만족하는 도큐먼트 검색하기
$or 연산자는 여러개의 필드 조건 중에서 어느 하나라도 만족하는 도큐먼트를 모두 검색한다. 위에서는 persons 컬렉션에서 name 필드값이 "syleemomo" 이거나, friends 필드값이 "길동"이거나 age 필드값이 24와 일치하는 모든 도큐먼트를 검색한다. $or 연산자는 필드조건을 중괄호({})로 감싸고, 배열 형태로 조건을 추가하면 된다.
$nor 연산자 - 서로 다른 필드조건 전부를 만족하지 않는 도큐먼트 검색하기
$nor 연산자는 여러개의 필드 조건을 모두 만족하지 않는 도큐먼트를 검색한다. 위에서는 persons 컬렉션에서 name 필드값이 "syleemomo" 이 아니고, friends 필드값이 "길동"이도 아니고 age 필드값이 24 도 아닌 조건을 모두 만족하는 도큐먼트를 검색한다. $nor 연산자는 필드조건을 중괄호({})로 감싸고, 배열 형태로 조건을 추가하면 된다.
$not 연산자 - 필드의 값이 해당 조건을 만족하지 않는 도큐먼트 검색하기
$not 연산자는 필드값이 주어진 조건을 만족하지 않는 모든 도큐먼트를 검색한다. 위에서는 persons 컬렉션에서 age 필드값이 30살을 넘지 않는 도큐먼트를 전부 검색한다. $not 연산자는 필드이름(age) 을 먼저 작성하고 $not 연산자에 중괄호({})로 조건을 넣어주면 된다.
위에서는 persons 컬렉션에서 name 필드값이 "syleemomo"와 일치하지 않는 모든 도큐먼트를 검색한다.
요소 쿼리
요소 쿼리를 실습하기 위하여 도큐먼트를 추가로 생성한다.
현재 도큐먼트 목록은 위와 같다.
$exists 연산자 - 조건에 주어진 필드이름을 가지고 있는 도큐먼트 검색하기
$exists 연산자는 조건에 주어진 필드이름을 가지고 있으면 검색이 된다. 위에서는 persons 컬렉션에서 hobby 라는 필드이름을 가지고 있는 도큐먼트들을 모두 검색한다.
$type - 필드값의 자료형이 일치하는 도큐먼트 검색하기
$type 연산자는 필드값의 자료형이 일치하는 도큐먼트를 검색한다. 위에서는 persons 컬렉션에서 friends 필드값의 자료형이 배열인 도큐먼트를 검색한다.
friends 필드값 전체의 자료형은 배열이지만 friends 필드값 배열 안에 있는 엘리먼트들은 문자열이므로 { $type: "string" } 으로 검색하더라도 검색이 된다.
다수의 자료형 타입을 검사하려면 위와 같이 배열형태로 작성하면 된다. friends 필드값은 배열이면서 동시에 문자열 엘리먼트를 가지고 있으므로 위와 같이 다수의 자료형을 검사해도 검색이 이루어진다.
같은 필드이름이 존재하더라도 자료형이 다르면 검색되지 않는다. 위에서는 name 필드값이 배열인 도큐먼트를 검색하지만 어떤 것도 해당사항이 없다.
$type 연산자가 배열인 경우에는 여러개의 자료형 중 어느 하나라도 만족하면 검색이 된다. 즉, OR 로 생각하면 된다.
평가 쿼리
$mod 연산자 - 필드값을 특정값으로 나누었을때 나머지가 일치하는 도큐먼트 검색하기
$mod 연산자는 필드값을 특정값으로 나눈 나머지가 일치하는 도큐먼트를 모두 검색한다. 위에서는 persons 컬렉션에서 age 필드값을 3으로 나눈 나머지가 0인 도큐먼트를 모두 검색한다.
$regex 연산자 - 정규표현식 조건에 일치하는 도큐먼트 검색하기
$regex 연산자는 정규표현식 조건에 매칭되는 도큐먼트를 검색한다. 정규표현식은 /조건/ 과 같은 형태로 설정하면 된다. 위에서는 persons 컬렉션에서 name 필드값이 "s" 문자로 시작하는 도큐먼트를 전부 검색한다. 캐럿(^)은 정규표현식에서 해당 문자로 시작하는지 검사한다.
$regex 연산자는 정규표현식 조건에 매칭되는 도큐먼트를 검색한다. 정규표현식은 /조건/ 과 같은 형태로 설정하면 된다. 위에서는 persons 컬렉션에서 name 필드값이 "a" 문자로 끝나는 도큐먼트를 전부 검색한다. 달러($)는 정규표현식에서 해당 문자로 끝나는지 검사한다.
$regex 연산자는 정규표현식 조건에 매칭되는 도큐먼트를 검색한다. 정규표현식은 /조건/ 과 같은 형태로 설정하면 된다. 위에서는 persons 컬렉션에서 name 필드값에 "i" 문자가 포함된 도큐먼트를 전부 검색한다.
$regex 연산자는 정규표현식 조건에 매칭되는 도큐먼트를 검색한다. 정규표현식은 /조건/ 과 같은 형태로 설정하면 된다. 위에서는 persons 컬렉션에서 name 필드값이 "g" 문자나 "h" 문자중에서 어느 하나를 포함하는 도큐먼트를 전부 검색한다. 대괄호([]) 안에 | 를 사용하면 OR 로 인식한다.
$text 연산자 - 특정 필드에서 키워드를 포함하는 도큐먼트 검색하기
우선 해당 연산자를 연습해보기 위하여 위와 같이 3개의 도큐먼트를 추가한다.
그리고 어떤 필드를 기준으로 검색을 할건지 createIndex() 로 미리 지정해줘야 한다.
그런데 필드를 잘못 지정하였다. 만약 검색하고 싶은 필드 지정을 잘못한 경우에는 일단 위와 같이 getIndexes() 로 인덱스가 적용된 상태를 확인하다.
그런 다음 dropIndex() 로 현재 필드 지정을 취소한다. 그리고 나서 다시 getIndexes() 로 확인해보면 취소된 것을 확인할 수 있다.
다시 hobby 필드를 기준으로 검색을 할 예정이므로 hobby 필드를 createIndex() 로 지정해준다.
hobby 필드값에 "something"이라는 문자열이 포함된 도큐먼트를 전부 검색한다.
키워드가 아니라 좀 더 정확한 문구를 검색하고 싶다면 위와 같이 \"검색문구\" 와 같이 검색문구 양쪽에 따옴표를 붙이고 역슬래쉬(\)로 이스케이핑해주어야 한다.
해당 필드에서 부분 문자열을 검색해주는것 같은데 검색이 완벽하지는 않은것 같다. build 를 검색하면 build 가 포함된 "building someting"을 잘 검색해주는듯 하였으나, some/ani/bril 등은 제대로 검색해주지 못하였다. 이때는 something/animal/briliant 와 갘은 완전한 키워드로 검색해야 검색이 되어서 어떤 경우에는 제대로 동작하지만 어떤 경우에는 제대로 동작하지 않는것 같다.
$where 연산자 - 자바스크립트 표현식 조건에 일치하는 도큐먼트 검색하기
$where 연산자는 자바스크립트 함수나 표현식으로 도큐먼트를 검색할 수 있다. 위에서는 persons 컬렉션에서 name 필드값이 사전순에서 "g"보다 뒤에 나오고, age 필드값이 30보다 작은 도큐먼트를 전부 검색한다.
db.[컬렉션 이름].drop() - 컬렉션(collection) 제거
컬렉션의 drop 메서드는 해당 컬렉션을 제거한다. 해당 컬렉션이 제대로 제거되었는지 확인하기 위해서는 해당 컬렉션의 find 메서드로 전체 도큐먼트를 조회해보거나 컬렉션 목록을 조회해보면 된다.
* MongoDB Comapss 도큐먼트 쿼리 연습
MongoDB 를 설치하면 MogoDB Compass 도 기본적으로 함께 설치되지만 MongoDB Compass 실행이 제대로 되지 않는다면 아래 사이트에서 따로 다운로드해서 설치하도록 한다.
MongoDB Compass 화면에서 Connect 메뉴를 선택하거나 최초 화면에서 New Connection 주소로 mongodb://localhost:27017 으로 설정하고 Connect 버튼을 클릭한다. 이렇게 하면 로컬에 존재하는 몽고 DB 서버에 접속한다. 몽고 DB 서버의 기본 포트는 27017 이다.
MongoDB Compass 에서 MongoDB 연결에 성공하면 보이는 초기화면이다. 기본적으로 admin, config, local 이라는 DB 가 이미 존재한다.
상단의 녹색버튼(Create database)을 클릭하면 위와 같은 팝업창이 뜬다. 여기서 Database Name 은 자신이 원하는 이름이나 닉네임(Nick name)으로 설정하면 된다. Collection Name 은 inventory 라고 입력하고 하단의 Create Database 버튼을 클릭하자!
syleemomo 라는 새로운 DB 가 맨 아래에 추가된 모습이 보인다. 새로 생성된 DB 를 클릭해보자!
위와 같이 팝업창에서 생성한 inventory 라는 새로운 컬렉션이 보인다. 새로 생성된 컬렉션을 클릭해보자!
위와 같이 inventory 컬렉션이 보인다. inventory 컬렉션에 아무 데이터도 없기 때문에 위와 같이 보인다. ADD DATA 라는 녹색버튼을 클릭하면 드롭다운 메뉴가 보이며, Insert Document 메뉴를 선택하면 아래와 같이 팝업창이 뜬다.
먼저 팝업창의 내용은 모두 지운다. 아래 데이터를 복사하여 팝업창에 붙여넣도록 한다. 팝업창에 도큐먼트를 붙여넣기 할때 반드시 필드명은 큰 따옴표(" ")로 감싸줘야 에러가 나지 않는다.
[
{ "item": "journal", "qty": 25, "size": { "h": 14, "w": 21, "uom": "cm" }, "status": "A" },
{ "item": "notebook", "qty": 50, "size": { "h": 8.5, "w": 11, "uom": "in" }, "status": "A" },
{ "item": "paper", "qty": 100, "size": { "h": 8.5, "w": 11, "uom": "in" }, "status": "D" },
{ "item": "planner", "qty": 75, "size": { "h": 22.85, "w": 30, "uom": "cm" }, "status": "D" },
{ "item": "postcard", "qty": 45, "size": { "h": 10, "w": 15.25, "uom": "cm" }, "status": "A" }
]
팝업창에 추가할 도큐먼트의 붙여넣기가 완료되면 하단의 Insert 버튼을 클릭한다.
도큐먼트가 추가되면 위와 같은 화면에 5개의 도큐먼트가 보인다. 이제 해당 도큐먼트를 이용하여 아래 링크에 나오는 도큐먼트 쿼리 연습을 따라해보자!
{ status: "D" }
inventory 컬렉션에서 status 필드의 값이 "D" 인 모든 도큐먼트를 쿼리한다.
SELECT * FROM inventory WHERE status = "D"
관계형 데이터베이스에서는 위와 동일한 쿼리이다. 결과는 아래와 같다.
{ status: { $in: [ "A", "D" ] } }
inventory 컬렉션에서 status 필드의 값이 "A" 나 "D" 인 모든 도큐먼트를 쿼리한다.
SELECT * FROM inventory WHERE status in ("A", "D")
관계형 데이터베이스에서는 위와 동일한 쿼리이다. 결과는 아래와 같다.
{ status: "A", qty: { $lt: 30 } }
inventory 컬렉션에서 status 필드의 값이 "A" 이고, qty 필드의 값이 30 보다 작은(less than) 모든 도큐먼트를 쿼리한다.
SELECT * FROM inventory WHERE status = "A" AND qty < 30
관계형 데이터베이스에서는 위와 동일한 쿼리이다. 결과는 아래와 같다.
{ $or: [ { status: "A" }, { qty: { $lt: 30 } } ] }
inventory 컬렉션에서 status 필드의 값이 "A" 이거나, 또는 qty 필드의 값이 30보다 작은(less than) 모든 도큐먼트를 쿼리한다.
SELECT * FROM inventory WHERE status = "A" OR qty < 30
관계형 데이터베이스에서는 위와 동일한 쿼리이다. 결과는 아래와 같다.
{ status: "A", $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ] }
먼저 inventory 컬렉션에서 status 필드의 값이 "A" 인 모든 도큐먼트를 쿼리한다. 즉, 네번째 쿼리결과가 된다. 그런 다음 qty 필드의 값이 30보다 작거나(less than) item 필드의 값에서 첫글자가 영어 알파벳 p 로 시작하는 도큐먼트를 쿼리한다. qty 필드의 값이 30보다 작은 journal 과 item 필드의 값의 첫글자가 p 로 시작하는 postcard 가 검색된다.
쿼리 명령어에는 필드의 값을 검색할때 위와 같이 정규표현식을 사용할 수 있다.
SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")
관계형 데이터베이스에서는 위와 동일한 쿼리이다. 결과는 아래와 같다.
db.[컬렉션 이름].updateOne(FILTER, UPDATE) - 하나의 도큐먼트 변경
컬렉션의 updateOne 메서드는 FILTER로 검색된 하나의 도큐먼트를 변경한다. 첫번째 인자 FILTER 는 변경할 도큐먼트를 찾는 쿼리 명령어가 들어가고, 두번째 인자 UPDATE 는 업데이트 명령어가 들어간다. 위 명령어는 persons 컬렉션에서 name 필드의 값이 "syleemomo" 인 도큐먼트를 검색한 다음, 해당 도큐먼트의 age 필드의 값을 100 으로 변경한다.
* 몽고 DB 업데이트 연습
mongodb compass 에서도 mongosh 터미널을 사용할 수 있다. 즉, 여기서도 명령어를 입력해서 db 를 제어할 수 있다.
필드 연산자
$set 연산자 - 특정 필드값 업데이트하기
[
{ "_id" : 1, "name" : "Central Perk Cafe", "Borough" : "Manhattan" },
{ "_id" : 2, "name" : "Rock A Feller Bar and Grill", "Borough" : "Queens", "violations" : 2 },
{ "_id" : 3, "name" : "Empire State Pub", "Borough" : "Brooklyn", "violations" : 0 }
]
위 데이터를 CMD 창에서 아래와 같이 추가하고 업데이트해보자! 또는 몽고 DB Compass 에서 CREATE COLLECTION 버튼을 클릭하여 restaurant 컬렉션을 생성하고 위 데이터를 복사하여 ADD DATA 버튼에서 Insert Document 메뉴를 클릭한 다음 팝업창에 붙여넣고 INSERT 해도 된다. (단, MogoDB Compass 에서 컬렉션 이름 붙여넣을때 restaurant 문자열 양쪽에 공백이 있는 상태에서 컬렉션을 생성하면 업데이트할때 제대로 되지 않는다. )
restaurant 컬렉션에 insertMany 메서드를 이용하여 주어진 도큐먼트를 추가한 다음 updateOne 메서드를 이용하여 하나의 도큐먼트를 업데이트한다. 위 명령어는 name 필드의 값이 "Central Perk Cafe"인 도큐먼트를 쿼리한 다음 해당 도큐먼트의 violations 필드 값을 3으로 업데이트한다. 이때 해당 도큐먼트에 violations 필드가 있으면 값만 변경하고, 없으면 violation 필드를 추가한 다음 값을 설정한다. 위 명령어는 후자의 경우이다. 또한, 일치하는 도큐먼트가 없으면, 업데이트는 일어나지 않는다.
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하면 restaurant 컬렉션이 추가되어 있고, name 필드의 값이 "Central Perk Cafe"인 도큐먼트를 확인해보면 해당 도큐먼트의 violations 필드 값이 3 으로 셋팅되어 있다.
db.products.insertOne(
{
_id: 100,
quantity: 250,
instock: true,
reorder: false,
details: { model: "14QQ", make: "Clothes Corp" },
tags: [ "apparel", "clothing" ],
ratings: [ { by: "Customer007", rating: 4 } ]
}
)
이번에는 products 컬렉션을 추가한다.
db.products.updateOne(
{ _id: 100 },
{ $set:
{
quantity: 500,
details: { model: "2600", make: "Fashionaires" },
tags: [ "coats", "outerwear", "clothing" ]
}
}
)
위 데이터를 CMD 창에서 아래와 같이 추가하고 업데이트해보자!
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하면 products 컬렉션이 추가되어 있고, quantity, details, tags 필드의 값이 updateOne 메서드의 업데이트 연산자 $set 에서 설정한 값으로 업데이트 된다.
db.products.updateOne(
{ _id: 100 },
{ $set: { "details.make": "Kustom Kidz" } }
)
필드값이 도큐먼트 객체(details 필드)인 경우 객체의 프로퍼티를 변경하려면 위와 같이 점(.)으로 선택하면 된다. 반드시 "details.make" 처럼 큰 따옴표로 감싸줘야 한다.
위 데이터를 CMD 창에서 아래와 같이 업데이트해보자!
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 details 필드를 보면 make 프로퍼티의 값이 "Kustom Kidz"로 업데이트 되었음을 확인할 수 있다.
db.products.updateOne(
{ _id: 100 },
{ $set:
{
"tags.1": "rain gear",
"ratings.0.rating": 2
}
}
)
필드값이 배열(tags, ratings 필드)인 경우 특정 배열요소를 변경하려면 위와 같이 점(.)으로 선택하면 된다. 반드시 "tags.1" 또는 "ratings.0.rating" 처럼 큰 따옴표로 감싸줘야 한다.
위 데이터를 CMD 창에서 아래와 같이 업데이트해보자!
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 tags 배열의 1번 인덱스 값을 보면 "rain gear"로 업데이트 되었으며 ratings 배열의 0번 인덱스의 rating 프로퍼티 값이 2로 업데이트 되었음을 확인할 수 있다.
$unset 연산자 - 특정 필드 제거하기
만약 ratings 필드의 0번째 도큐먼트에서 by 필드를 제거하려면 어떻게 하면 될까?
db.products.updateOne( {_id: 100}, { $unset: {"ratings.0.by": 1} } )
위와 같이 하면 된다. ratings 필드는 배열이며, ratings 필드의 배열요소 1개는 객체이므로 점(.)으로 접근하면 된다.
db.members.insertMany( [
{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, comments: [ "reminder: ping me at 100pts", "Some random comment" ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
] )
이번에는 members 컬렉션을 추가한다. MongoDB Compass 에서 아래와 같은 데이터를 복사해서 Insert Doucment 로 추가하면 오류가 발생한다. 이유는 comments 필드는 큰 따옴표로 감싸줘야 한다. 또한, MongoDB Compass 에서는 ISODate 같은 함수가 제대로 동작하지 않는다. ISODate 함수를 큰 따옴표로 묶어주고 내부 문자열을 작은 따옴표로 묶어주면 문법 오류는 나지 않지만, 결국 ISODate 함수는 제대로 동작하지 않는다.
[
{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, comments: [ "reminder: ping me at 100pts", "Some random comment" ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
]
db.members.updateOne(
{ _id: 1 },
[
{ $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
{ $unset: [ "misc1", "misc2" ] }
]
)
위 데이터를 CMD 창에서 아래와 같이 업데이트해보자!
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 members 컬렉션을 확인해보자!
먼저 status 필드값이 "Modified"로 업데이트된다. comments: [ "$misc1", "$misc2" ] 에 의하여 misc1, misc2 필드값이 comments 배열의 요소로 삽입된다. $misc1 은 misc1 필드의 값을 의미한다. lastUpdate: "$$NOW" 에 의하여 현재시간이 lastUpdate 필드값으로 설정된다. 마지막으로 $unset 연산자에 의하여 misc1, misc2 필드는 제거된다.
$misc1, $misc2 라는 필드의 값을 읽으려면 반드시 배열([]) 구문 안에 { $set: } 구문이 들어있어야 한다.
friends: [{name, age}, {name, age}] 처럼 필드가 객체들의 배열인 경우 friends 배열안에 존재하는 모든 객체의 name 필드를 수정하려면 [{ $set: { 'friends.name': "변경" }}] 로 하면 된다. 즉, 대괄호를 붙이면 friends 는 배열안의 객체를 의미한다. { $set: { 'friends.$[].name': "변경" }} 이라고 해서 대괄호를 붙이지 않으면 friends 는 배열 자체를 의미한다. 그래서 배열 안의 모든 객체에 대하여 name 필드를 변경하려면 $[] 를 붙여주면 된다.
$setOnInsert 연산자 - 업데이트하려고 하는 도큐먼트가 존재하지 않는 경우만 필드값 삽입하기
db.products.updateOne(
{ _id: 1 },
{
$set: { item: "apple" },
$setOnInsert: { defaultQty: 100 }
},
{ upsert: true }
)
CMD 창에서 위와 같이 작성하여 업데이트를 해보자!
위와 같이 업데이트를 하려고 했지만 새로운 도큐먼트가 생성되고 추가된다. upsert 는 이름에서 유추할 수 있듯이 update 와 insert 를 합친 말이다. upsert 는 그러므로 업데이트하려고 하는 도큐먼트가 존재하면 업데이트를 수행하고, 도큐먼트가 존재하지 않으면 컬렉션에 새로운 도큐먼트를 생성하고 추가한다. products 컬렉션에 _id: 1 인 도큐먼트는 존재하지 않으므로 새로운 도큐먼트를 생성하고 추가한다. $setOnInsert 연산자는 위의 경우처럼 도큐먼트가 새로 추가될때만 동작한다.
db.products.updateOne(
{ _id: 100 },
{
$set: { item: "orange" },
$setOnInsert: { defaultQty: 100 }
},
{ upsert: true }
)
CMD 창에서 위와 같이 작성하여 업데이트를 해보자!
products 컬렉션에 _id: 100 인 도큐먼트는 이미 존재하므로 업데이트가 일어난다. 이때 $set 연산자는 동작하기 때문에 item 필드가 추가된다. 하지만 $setOnInsert 연산자는 동작하지 않는다. 그래서 defaultQty 필드는 추가되지 않는다. 왜냐하면 $setOnInsert 는 앞서 설명하였듯이 이미 존재하는 도큐먼트에는 적용하지 않기 때문이다.
$rename 연산자 - 필드명 변경하기
restaurant 컬렉션의 필드명 Borough 는 뭔가 이해가 되지 않는 필드명이다.
db.restaurant.updateMany( {}, { $rename: { "Borough": "city" } } )
CMD 창에서 위와 같이 작성하여 필드명을 변경해보자!
위와 같이 필드명이 Borough 에서 city 로 변경된 것을 확인할 수 있다.
products 컬렉션에서 _id: 100 인 도큐먼트에서 임베디드 도큐먼트인 details 의 model 필드명을 star 로 변경하려면 아래와 같이 작성하면 된다.
db.products.updateOne(
{ _id: 100 },
{ $rename: { "details.model": "details.star" } }
)
$mul 연산자 - 필드값을 일정 배수만큼 곱하기
db.inventory.updateMany(
{ status: "A" },
{ $mul:
{
qty: 3,
"size.h": 10
}
}
)
위 코드는 inventory 컬렉션에서 status 필드값이 "A" 인 모든 도큐먼트를 찾은 다음, qty 필드값은 3배를 곱해주고, 임베디드 도큐먼트인 size 의 h 필드값은 10배를 곱해준다.
결과는 위와 같다.
$max 연산자 - 특정 필드값을 최대값으로 유지하기
현재 inventory 컬렉션은 위와 같다.
db.inventory.updateMany(
{ },
{ $max: { qty: 97 } }
)
CMD 창에서 위와 같이 작성하여 inventory 컬렉션을 업데이트해보자!
현재 inventory 컬렉션에 있는 모든 도큐먼트에서 qty 값이 97보다 작은 값을 97로 업데이트한다. 물론 현재 qty 값이 97보다 크다면 업데이트는 이루어지지 않는다. item 필드값이 "journal" 과 "planner" 인 도큐먼트의 qty 필드값만 97로 변경된다.
$inc 연산자 - 필드값을 정해진 값만큼 더하기
현재 inventory 컬렉션은 위와 같다.
db.inventory.updateMany(
{ },
{ $inc: { qty: 100, "size.w": 10 } }
)
CMD 창에서 위와 같이 작성하여 inventory 컬렉션을 업데이트해보자!
결과는 위와 같다. $inc 연산자는 qty 필드값을 100만큼 더하고, 임베디드 도큐먼트인 size 의 w 필드값을 10만큼 더한다. 물론 마이너스(-)값도 사용가능하다.
$currentDate 연산자 - 필드값을 현재 날짜로 변경하기
현재 members 컬렉션에서 _id: 2 인 도큐먼트는 lastUpdate 필드값이 현재 날짜가 아니다. 현재 날짜로 변경해보자!
db.members.updateOne(
{ _id: 2 },
{
$currentDate: {
lastUpdate: true,
},
$set: {
status: "Modified"
}
}
)
CMD 창에서 위와 같이 작성하여 members 컬렉션의 특정 도큐먼트를 업데이트해보자!
members 컬렉션에서 _id: 2 인 도큐먼트의 lastUpdate 필드값이 현재 날짜와 시간으로 변경되었다. 물론 그리니치 시간이라 9시간을 더해줘야 한국 현지시간이 된다. 그리고 statius 필드값은 "Modified" 로 변경되었다.
배열 연산자
$push 연산자 - 필드값이 배열인 경우 새로운 원소값 추가하기
db.students.insertOne( { _id: 1, scores: [ 44, 78, 38, 80 ] } )
이번에는 students 컬렉션을 추가한다.
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: 89 } }
)
위 데이터를 CMD 창에서 아래와 같이 업데이트해보자!
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 students 컬렉션을 확인해보자! scores 필드값(배열)의 마지막 요소로 89 가 추가된다.
db.students.insertMany( [
{ _id: 2, scores: [ 45, 78, 38, 80, 89 ] } ,
{ _id: 3, scores: [ 46, 78, 38, 80, 89 ] } ,
{ _id: 4, scores: [ 47, 78, 38, 80, 89 ] }
] )
students 컬렉션에 3명의 학생을 더 추가해보자!
위와 같이 추가된 학생에도 scores 필드가 존재하며 자료형은 배열이다. 여기서 추가된 학생 3명의 scores 필드(배열)에 같은 값을 동시에 추가하고 싶으면 아래와 같이 하면 된다.
$push 연산자 - 필드값이 배열인 경우 새로운 원소값을 여러개의 도큐먼트에 한번에 추가하기
db.students.updateMany(
{ },
{ $push: { scores: 95 } }
)
CMD 창에서 위와 같이 students 컬렉션을 업데이트해보자!
모든 도큐먼트의 scores 배열에 95가 추가된 것을 확인할 수 있다.
아래 수업내용의 일관성을 위하여 mongodb compass 에서 _id: 1 도큐먼트의 scores 배열의 마지막 값 95는 삭제하자.
$each 수정자 (modifier) - 필드값이 배열인 경우 다수의 엘리먼트를 배열에 추가하기
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: { $each: [ 90, 92, 85 ] } } }
)
$each 는 수정자(modifier)라고 한다. $each 수정자를 사용하면 배열에 다수의 배열요소를 추가할 수 있다.
위 데이터를 CMD 창에서 아래와 같이 업데이트해보자!
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 students 컬렉션을 확인해보자! scores 필드값(배열)에 $each 로 설정한 배열의 값들이 scores 필드(배열)에 추가된다.
$push 연산자의 특징 - 중복허용
db.students.updateOne( { _id: 1 }, { $push: { scores: { $each: [ 90, 92 ] } } } )
하지만 위 명령어를 입력하면 아래와 같이 이미 90, 92 가 존재함에도 불구하고 다시 90, 92를 추가한다. 즉, 중복을 허용한다.
$addToSet 연산자 - 필드값이 배열인 경우 중복없이 배열에 값 추가하기
그렇다면 중복을 허용하지 않으려면 어떻게 하면 될까?
db.students.updateOne( { _id: 1 }, { $addToSet: { scores: { $each: [ 90, 37, 92 ] } } } )
위와 같이 $addToSet 연산자를 사용하면 된다. 이렇게 하면 scores 필드(배열)에 $each 수정자로 주어진 값이 존재하면 추가되지 않는다. 즉, scores 필드(배열)에 존재하지 않는 37만 추가된다.
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 students 컬렉션을 확인해보자! scores 필드값(배열)에 $each 수정자로 주어진 값 중 90 과 92는 이미 존재하므로 추가되지 않는다. 즉, scores 필드(배열)에 존재하지 않는 37만 추가된다.
$push 연산자를 다수의 수정자(modifier)와 함께 사용하기
그럼 _id: 1 인 도큐먼트의 scores 배열에 여러개의 배열요소를 추가한 다음 내림차순 정렬하고 5개만 DB 에 저장하려면 어떻게 하면 될까?
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: {
$each: [ 2, 124, 49 ],
$sort: -1,
$slice: 5
} } }
)
$each, $sort, $slice 는 모두 수정자(modifier)라고 한다. 수정자는 연산자의 기능을 더 풍부하게 해준다. 위와 같이 $sort 수정자를 사용하면 해당 필드(scores)에 대하여 정렬이 된다. 1은 오름차순 정렬이고, -1은 내림차순 정렬이다. $slice 연산자는 해당 필드(scores)에서 앞에서부터 5개의 배열요소만 잘라서 다시 DB 에 저장한다.
MongoDB Compass 에서 왼쪽 메뉴에서 새로고침 버튼을 클릭하고 students 컬렉션을 확인해보자! scores 필드값(배열)에 2, 124, 49 가 추가된 다음 내림차순으로 정렬한다. 그런 다음 5개의 요소만 추출하여 다시 DB 에 저장한다.
$pop 연산자 - 도큐먼트의 필드값이 배열인 경우 배열의 첫번째나 마지막 엘리먼트 제거하기
그럼 scores 배열의 첫번째나 마지막 요소를 제거하려면 어떻게 하면 될까?
db.students.updateOne( { _id: 1 }, { $pop: { scores: 1 } } )
$pop 연산자는 주어진 필드(scores)에서 첫번째나 마지막 요소를 제거한다. 1이면 마지막 요소를 제거하고, -1이면 첫번째 요소를 제거한다.
$position 수정자 - 도큐먼트의 필드값이 배열인 경우 배열의 특정 위치에 엘리먼트 추가하기
db.students.insertOne( { "_id" : 5, "scores" : [ 100 ] } )
students 컬렉션에 한명의 학생을 더 추가해보자!
추가한 학생의 scores 배열 맨 앞에 새로운 배열요소들을 추가하려면 아래와 같이 하면 된다.
db.students.updateOne(
{ _id: 5 },
{
$push: {
scores: {
$each: [ 50, 60, 70 ],
$position: 0
}
}
}
)
CMD 창에서 위와 같이 작성하여 새로 추가한 학생의 scores 배열에 새로운 배열요소를 추가해보자!
$position: 0 의 위치는 배열의 맨 앞이다. 해당 위치에 50, 60, 70 이 추가된 것을 확인할 수 있다.
db.students.updateOne(
{ _id: 5 },
{
$push: {
scores: {
$each: [ 20, 30 ],
$position: 2
}
}
}
)
scores 배열의 중간에 새로운 배열요소를 삽입하려면 위와 같이 작성하면 된다.
scores 배열의 2번 인덱스 위치에 새로운 배열요소를 추가하였다.
db.students.updateOne(
{ _id: 5 },
{
$push: {
scores: {
$each: [ 90, 80 ],
$position: -2
}
}
}
)
자바스크립트의 splice 메서드처럼 마이너스 인덱스값을 설정하는 것도 가능하다.
$position: -2 는 4번 인덱스 위치이므로 해당 위치에 새로운 배열요소를 삽입한다.
$pull 연산자 - 도큐먼트의 필드값이 배열인 경우 배열에서 조건과 일치하는 배열원소 제거하기
db.stores.insertMany( [
{
_id: 1,
fruits: [ "apples", "pears", "oranges", "grapes", "bananas" ],
vegetables: [ "carrots", "celery", "squash", "carrots" ]
},
{
_id: 2,
fruits: [ "plums", "kiwis", "oranges", "bananas", "apples" ],
vegetables: [ "broccoli", "zucchini", "carrots", "onions" ]
}
] )
$pull 연산자의 실습을 위하여 CMD 창에서 위와 같이 작성하여 stores 컬렉션을 추가한다.
db.stores.updateMany(
{ },
{ $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } }
)
$pull 연산자를 이용하여 위와 같이 작성한 다음 stores 컬렉션의 도큐먼트들을 업데이트해보자!
$pull 연산자는 stores 컬렉션의 모든 도큐먼트에서 fruits 배열에서 "apples" 와 "oranges" 를 제거하고, vegetables 배열에서 "carrots" 를 제거한다.
db.profiles.insertOne( { _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] } )
다음 실습을 위하여 profiles 컬렉션을 추가한다. 하나의 도큐먼트에는 votes 필드가 배열로 존재한다.
db.profiles.updateOne( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )
$pull 연산자를 이용하여 위와 같이 작성한 다음 profiles 컬렉션의 도큐먼트들을 업데이트해보자!
$pull 연산자는 votes 배열에서 6보다 크거나 같은 값을 제거한다.
try {
db.profilesBulkWrite.bulkWrite( [
{
insertOne: {
"document": { _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] }
}
},
{
updateOne: {
"filter": { _id: 1 },
"update": { $pull: { votes: { $gte: 6 } } }
}
},
{
updateOne: {
"filter": {_id: 1},
"update": { $pull: { votes: { $lte: 3 } } }
}
}
] );
} catch (e) {
print(e);
}
위와 같이 작성하여 profilesBulkWrite 컬렉션을 생성함과 동시에 여러번의 업데이트를 동시에 실행해보자! 우선 profilesBulkWrite 컬렉션을 생성한다. 다음으로 _id: 1 인 도큐먼트의 votes 배열에서 6보다 크거나 같은 배열요소를 모두 제거한다. 다음으로 _id: 1 인 도큐먼트의 votes 배열에서 3보다 작거나 같은 배열요소를 모두 제거한다.
위와 같이 votes 배열에서 5만 남고 모두 제거된다. mongo compass 는 한번 껐다가 재실행해야 profilesBulkWrite 컬렉션이 추가되었음을 확인할 수 있다.
$pull 연산자 - 도큐먼트의 필드값이 도큐먼트의 배열인 경우 배열에서 조건과 일치하는 도큐먼트 제거하기
db.survey.insertMany([
{
_id: 1,
results: [
{ item: "A", score: 5 },
{ item: "B", score: 8 }
]
},
{
_id: 2,
results: [
{ item: "C", score: 8 },
{ item: "B", score: 4 }
]
}
] )
실습을 위하여 아래와 같이 survey 컬렉션을 추가한다.
db.survey.updateMany(
{ },
{ $pull: { results: { score: 8 , item: "B" } } }
)
CMD 창에서 위와 같이 작성하여 survey 컬렉션을 업데이트해보자!
$pull 연산자는 survey 컬렉션의 results 배열에서 score: 8 item: "B" 를 모두 포함하고 있는 도큐먼트를 찾아서 제거한다. 이때 순서는 상관이 없다.
_id: 2 인 도큐먼트도 부분적으로 item: "B" 와 score: 8 을 포함하지만 모두 포함하고 있지는 않기 때문에 제거되지는 않았다.
만약 여러개의 조건중 어느 하라도 만족하는 도큐먼트를 제거하려면 어떻게 하면 될까?
db.survey.updateMany(
... {},
... { $pull: { results: { $or: [{score: 4}, {item: "A"}] }}}
... )
CMD 창에서 위와 같이 작성하여 survey 컬렉션을 업데이트해보자!
$pull 연산자는 survey 컬렉션의 results 배열에서 score 필드값이 4이거나, item 필드값이 "A" 인 두 조건중 어느 하라라도 일치하는 도큐먼트를 찾아서 제거한다. 이때 순서는 상관이 없다.
$pullAll 연산자 - 도큐먼트의 필드가 배열인 경우 배열에서 주어진 값을 모두 제거하기
db.survey.insertOne( { _id: 3, scores: [ 0, 2, 5, 5, 1, 0 ] } )
$pullAll 연산자 실습을 위하여 새로운 도큐먼트를 추가한다.
db.survey.updateOne( { _id: 3 }, { $pullAll: { scores: [ 0, 5 ] } } )
CMD 창에서 위와 같이 작성하여 survey 컬렉션의 마지막 도큐먼트를 업데이트해보자!
$pullAll 연산자는 배열에 주어진 값 각각에 대하여 scores 배열에서 모두 제거한다. 즉, scores 배열에서 0 과 5 가 중복이 되든지 되지 않던지 모두 지운다. $pull 연산자는 주어진 검색조건을 만족하는 배열요소를 제거하는데 비해 $pullAll 연산자는 주어진 값과 일치하는 배열요소를 제거한다는데 차이점이 있다.
$setIntersection, $setUnion 연산자 - 배열 필드의 중복 제거하기
$setIntersection 은 여러개의 배열에서 공통적으로 포함된 배열요소만 추출하고, $setUnion 은 여러개의 배열에 하나로도 존재하는 배열요소를 합친다. $setIntersection 은 다수의 배열의 교집합을 구하고, $setUnion 은 다수의 배열에서 합집합을 구한다. 하지만 단일 배열인 경우 중복을 제거하는데 이용이 가능하다.
위 도큐먼트의 scores 배열에서 중복을 제거하려면 어떻게 하면 될까?
db.students.updateOne({_id: 1}, [{ $set: { scores: { $setIntersection: ["$scores"] }}}])
setIntersection 이라는 연산자를 이용하면 $scores (scores 배열) 에서 중복을 제거하고 새로운 배열에 담는다. 그런 다음 scores 배열을 $set 연산자에 의하여 중복이 제거된 새로운 배열로 설정한다. 배열요소의 순서는 무시되거나 규칙적이지 않다.
db.students.updateOne({_id: 1}, [{ $set: { scores: { $setUnion: ["$scores"] }}}])
$setUnion 이라는 연산자를 이용해도 중복이 제거된다.
$setIntersection 연산자 - 중복을 제거하고 두 배열의 공통적인 배열요소만 추출해서 합치기
위와 같은 students 컬렉션에서 _id:2 인 도큐먼트의 scores 배열과 evaluations 배열의 중복을 제거하고 공통적인 배열요소만 추출해서 하나의 배열로 합치려면 아래와 같이 하면 된다.
db.students.updateOne(
{ _id: 2 },
[
{ $set: {
intersecArray: { $setIntersection: ["$scores", "$evaluations"] }
}
}
]
)
결과는 아래와 같이 scores 배열과 evaluations 배열에서 교집합 배열인 [78, 89] 를 intersecArray 필드값으로 지정한다.
$avg - 배열에서 평균 구하기
그럼 students 컬렉션에서 특정 도큐먼트의 scores 배열에서 평균을 내려면 어떻게 하면 될까?
db.students.updateOne(
... {_id: 5},
... [
{ $set: {
scores: { $avg: "$scores" }
}
}
]
)
CMD 창에서 위와 같이 작성하여 students 컬렉션에서 _id: 5 인 도큐먼트의 scores 배열요소들의 평균을 구해보자!
위와 같이 _id: 5 인 도큐먼트의 scores 배열요소들끼리 평균을 구한 다음, 다시 scores 필드값을 평균값으로 설정한다. 500/8 을 해서 62.5가 된다.
* $multiply - 필드의 값에 대한 곱셈 수행하기
db.clothes.insertMany([
{ "_id" : 1, "item" : "abc", "price" : 10, "fee" : 2, "discount" : 5, "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : 20, "fee" : 1, "discount" : 2, "date" : ISODate("2014-03-01T09:00:00Z") }
])
해당 clothes 컬렉션은 아래와 같이 Mongo Compass 에서 확인할 수 있다.
해당 컬렉션에서 price 필드값과 fee 필드값을 곱해서 새로운 totalPrice 필드에 추가하려면 아래와 같이 하면 된다.
db.clothes.updateMany({},
[
{ $set: {
'totalPrice': { $multiply: ['$price', '$fee'] }
}}
])
* $subtract - 필드값에 대한 뺄샘 수행하기
해당 컬렉션에서 totalPrice 필드값에서 discount 필드값을 빼고, discountedPrice 필드에 결과를 저장하려면 아래와 같이 하면 된다.
db.clothes.updateMany({},
[
{ $set: {
'discountedPrice': { $subtract: ['$totalPrice', '$discount'] }
}}
])
db.[컬렉션 이름].deleteOne(FILTER, OPTION) - 하나의 도큐먼트 제거
컬렉션의 deleteOne 메서드는 FILTER 로 도큐먼트를 쿼리한 다음 해당하는 도큐먼트를 제거한다.
db.[컬렉션 이름].remove({}) - 전체 도큐먼트 제거
컬렉션의 remove 메서드는 인자로 중괄호({})가 설정되면 해당 컬렉션에 존재하는 모든 도큐먼트를 제거한다.
https://m.blog.naver.com/ijoos/221312444591
* 연습과제 1
아래 데이터는 수업 시간에 다룬 inventory 컬렉션이다. 해당 데이터를 CMD 창이나 MongoDB Compass 를 이용하여 데이터베이스에 추가한 다음, 캡쳐화면과 같은 결과가 나오도록 해보자! 즉, status 필드가 "D" 인 모든 도큐먼트를 검색한 다음, size 필드의 h, w 프로퍼티 값을 이용하여 status 필드에 그대로 복사해서 status 필드값이 배열이 되도록 해보자! (단, updateOne 대신에 updateMany 메서드를 사용해야 한다. )
[
{ "item": "journal", "qty": 25, "size": { "h": 14, "w": 21, "uom": "cm" }, "status": "A" },
{ "item": "notebook", "qty": 50, "size": { "h": 8.5, "w": 11, "uom": "in" }, "status": "A" },
{ "item": "paper", "qty": 100, "size": { "h": 8.5, "w": 11, "uom": "in" }, "status": "D" },
{ "item": "planner", "qty": 75, "size": { "h": 22.85, "w": 30, "uom": "cm" }, "status": "D" },
{ "item": "postcard", "qty": 45, "size": { "h": 10, "w": 15.25, "uom": "cm" }, "status": "A" }
]
연습과제 2
연습과제 1에서 추가된 inventory 컬렉션과 updateMany 메서드를 이용하여 캡쳐화면과 같은 결과가 나오도록 데이터를 업데이트해보자! 즉, status 필드값이 "A"이고 qty 필드값이 50보다 작은 모든 도큐먼트를 검색한 다음, size 필드의 h 프로퍼티 값을 "big" 이라는 문자열로 변경해보자!
* 연습과제 3
연습과제 1에서 추가된 inventory 컬렉션과 updateOne 메서드를 이용하여 qty 필드값이 100 인 도큐먼트의 item 필드값을 "아이템" 이라는 문자열로 변경해보자!
* 연습과제 4
연습과제 1에서 추가된 inventory 컬렉션과 updateMany 메서드를 이용하여 모든 도큐먼트에 users 라는 필드를 추가하고, users 필드의 값을 ["victoria", "hanna", "danniel"] 라는 배열로 설정해보자! (단, 모든 도큐먼트를 선택하려면 updateMany 메서드의 첫번째 파라미터에 빈 객체 {} 를 전달하면 된다.)
* 연습과제 5
inventory 컬렉션과 updateMany 메서드를 이용하여 size 필드의 w 프로퍼티 값이 11 보다 크고 30보다 작은 모든 도큐먼트를 검색한 다음, users 필드(배열)에 "영희" 와 "철수" 라는 문자열을 배열요소로 추가해보자! (단, 연습과제 4번을 먼저 풀이한 다음 해당 문제를 푼다.)
* 연습과제 6
inventory 컬렉션과 updateMany 메서드를 이용하여 item 필드의 값이 "journal" 이나 "notebook"인 모든 도큐먼트를 검색한 다음, 해당 도큐먼트의 status 필드를 제거해보자!
연습과제 7번부터는 아래에 주어진 영화목록(movies) 컬렉션을 사용하도록 한다.
연습과제 7
movies 컬렉션에서 updateMany 메서드를 이용하여 아래와 같이 info 필드를 추가하고, 해당 배열의 값들은 year, rating, runtime 필드의 값들로 채우자!
연습과제 8
movies 컬렉션에서 updateMany 메서드를 이용하여 mpa_rating 필드를 제거해보자!
연습과제 9
movies 컬렉션에서 id 필드값이 61230인 도큐먼트를 찾고, 해당 도큐먼트에서 아래와 같이 필드값을 변경해보세요!
연습과제 10
movies 컬렉션에서 torrents 필드에 있는 모든 임베디드 도큐먼트의 seeds 필드를 runtime 필드값으로 설정하고, peers 필드를 year 필드값으로 설정하세요!
연습과제 11
movies 컬렉션에서 영화 상영시간(runtime)이 11의 배수인 모든 도큐먼트를 검색하고, 해당 도큐먼트 목록에서 date_uploaded 필드를 현재시간으로 업데이트해보세요!
연습과제 12
movies 컬렉션에서 모든 도큐먼트를 검색하고, torrents 필드의 모든 임베디드 도큐먼트에 대하여 seeds 필드는 2배를 곱해주고, peers 필드는 3을 더해준다. (아래 자료 참고)
연습과제 13
movies 컬렉션에서 genres 에 "Comedy", "Action" 둘다 포함하지 않는 도큐먼트를 찾고, 해당 도큐먼트의 genres 필드에 "Comedy", "Action", "추가함" 배열요소를 추가해보자!
연습과제 14
movies 컬렉션에서 모든 도큐먼트를 검색하고, genres 필드를 오름차순 정렬하세요!
연습과제 15
movies 컬렉션의 모든 도큐먼트에 대하여 genres 배열에서 "추가함"이라는 문자열을 제거하세요!
연습과제 16
movies 컬렉션에서 torrents 배열의 모든 도큐먼트에 대하여 video_codec 이 "x264" 이고, audio_channels 가 "2.0" 인 도큐먼트를 배열에서 제거하세요!
연습과제 17
movies 컬렉션에서 모든 도큐먼트에 totalSize 필드를 추가하고, 해당 필드의 값을 rating 과 runtime 필드값을 곱해서 설정하세요!
쿼리연습과제
아래에 주어진 파일을 다운로드하고, MongoDB Compass 에서 movies 컬렉션을 생성하고, 아래 문서의 JSON 파일을 임포트하도록 하자!
연습과제 1
해당 컬렉션에서 title 필드에 "er" 이라는 문자열을 포함하고 있는 모든 도큐먼트를 쿼리해보세요! 쿼리갯수는 8개입니다.
연습과제 2
해당 컬렉션에서 발매년도가 2020년보다 최근에 나온 영화를 모두 쿼리해보세요! 쿼리갯수는 9개입니다.
연습과제 3
해당 컬렉션에서 발매년도가 2005년과 2007년 사이인 모든 영화를 쿼리하세요! 쿼리갯수는 5개입니다.
연습과제 4
해당 컬렉션에서 장르에 Comedy 나 Horror 를 포함하는 모든 영화를 쿼리하세요! 쿼리갯수는 9개입니다.
연습과제 5
해당 컬렉션에서 영화 상영시간을 5로 나눈 나머지가 0인 모든 영화를 쿼리하세요! 쿼리갯수는 6개입니다.
연습과제 6
해당 컬렉션에서 평점이 7점 이상이고, 발매년도가 2020년 초과인 모든 영화를 쿼리하세요! 쿼리갯수는 2개입니다.
연습과제 7
해당 컬렉션에서 summary 필드에 "in the" 가 포함된 영화를 전부 쿼리하세요! 쿼리갯수는 5개입니다.
연습과제 8
해당 컬렉션에서 자막이 nl 이거나, pt 인 모든 영화를 쿼리하세요! 쿼리갯수는 3개입니다.
연습과제 9
해당 컬렉션에서 장르에 로맨스가 포함되어 있고, 발매년도가 2015년과 2023년 사이인 모든 영화를 쿼리하세요! 쿼리갯수는 2개입니다.
연습과제 10
해당 컬렉션에서 영화제목(title) 필드의 문자열 길이가 12보다 작은 영화를 쿼리하세요! 쿼리갯수는 3개입니다.
연습과제 11
해당 컬렉션에서 발매년도가 2013년도보다 오래되지 않고, 상영시간이 100분보다 짧지 않은 영화를 전부 쿼리하세요! 쿼리갯수는 2개입니다.
연습과제 12
해당 컬렉션에서 장르에 "Horror", "Action", "Romance", "Drama", "Mystery" 를 포함하지 않는 영화를 모두 쿼리하세요! 쿼리갯수는 6개입니다.
연습과제 13
해당 컬렉션에서 장르의 갯수가 4개인 모든 영화를 쿼리하세요! 쿼리갯수는 2개입니다.
연습과제 14
해당 컬렉션에서 영화제목(title)에 하이픈(-)이 2개 들어있는 영화를 쿼리하세요! 쿼리갯수는 1개입니다.
연습과제 15
해당 컬렉션에서 영화제목(title)에 콜론(:)을 포함하는 모든 영화를 쿼리하세요1 쿼리갯수는 6개입니다.
'데이터베이스 > MongoDB 수업' 카테고리의 다른 글
0. 몽고DB - 설치 가이드 (최신) (0) | 2024.04.03 |
---|---|
3. 몽고 DB - aggregation (집계, 합산) (0) | 2023.08.02 |
2. 몽고 DB - 배열 쿼리 연습 (0) | 2021.10.08 |