...
데이터베이스 명령어
데이터베이스 생성
show dbs -- 데이터베이스 리스트가 출력
db -- 현재 사용하고 있는 데이터베이스 출력
db.stats() -- 현재 사용 하고 있는 데이터 베이스 정보 출력
데이터베이스 사용
use database -- 데이터베이스 사용 혹은 생성(존재 하지 않을 경우 생성)
-- use 를 통해 생성된 데이터베이스는 그 안에 최소 한개의 Document 가 존재해야 show dbs 를 통해 확인할 수 있다.
데이터베이스 삭제
db.dropDatabase() -- 데이터베이스를 삭제
-- 이 명령어는 use DATABASE_NAME 를 통해 지울 데이터베이스가 선택되어 있어야 합니다.
컬렉션 명령어
컬렉션 생성
// db.createCollection( name [, options] )
// name 은 Collection 의 이름을 지정하는 인자이고, options 는 Collection 의 설정을 변경해주는 인자
db.createCollection("book")
db.createCollection(
"book",
{
capped:true,
size:6142800,
max:10000
}
)
[createCollection options]
Field | Type | 설명 |
capped | Boolean | boolean타입, true로 설정 시 활성화, capped collection이란 고정된 크기(fixed size)를 가진 컬렉션, 사이즈가 초과시 가장 오래된 데이터를 덮어씀 |
size | number | capped가 true일 경우 필수로 설정 해야되는 값이며, 해당 컬렉션의 최대사이즈(단위:byte) |
max | number | 해당 컬렉션에 추가 할 수 있는 최대 document 갯수 |
컬렉션 조회
show collections -- 컬렉션(테이블) 보기
컬렉션 삭제
db.book.drop()
// test데이터베이스의 book이라는 collection을 제거
// 제거전에는 필수로 use database를 이용하여 현재 데이터베이스를 설정 해야된다.
다큐먼트 명령어
데이터 삽입 (insert)
- insert- 단일 또는 다수의 Document를 입력할 때 사용. 만일 컬렉션이 존재하지않는다면 자동으로 생성재주고 insert해준다.
- insertOne - 단일 Document를 입력할 때 사용
- insertMany - 다수의 Document를 입력할 때 사용
db.book.insert({"name":"abc"})
// 여러개를 넣을때는 배열로 묶는다.
db.book.insert([
{"name":"abc"},
{"name":"def"}
])
db.book.insert({
"name":"A",
"hits":100,
"auther":[
{"name":"park"},
{"name":"lee"}
]
});
db.book.insert({
"name":"B",
"hits":50,
"auther":[
{"name":"kim"}
]
});
db.book.insert({
"name":"C",
"hits":30,
"auther":[
{"name":"kim"},
{"name":"choi"}
]
});
데이터 조회 (find)
// Document 리스트를 확인
db.books.find()
// 다큐먼트를 좀더 깔끔하게 보여준다.
db.book.find().pretty()
// name이 A인 document을 조회한다.
db.book.find({"name":"A"}).pretty()
id 필드의 ObjectId("618ejhsdke8121kf")는 몽고DB에서 자동으로 넣어주는 고유값.
db.monsters.findOne({ name: 'Slime' });
// 단 하나만 찾고 싶을 때 사용. find(...)[0]과도 같다.
// find 메소드로 찾은 것 중에 첫 번째 것을 선택
논리 연산자
{ 필드: { $gt: 값 } } // 필드 > 값
{ 필드: { $lt: 값 } } // 필드 < 값
{ 필드: { $gte: 값 } } // 필드 >= 값
{ 필드: { $lte: 값 } } // 필드 <= 값
{ 필드: { $eq: 값 } } // 필드 == 값
{ 필드: { $ne: 값 } } // 필드 != 값
{ 필드: { $in: [ 값1, 값2, 값3, ... ] } // 필드 == (값1 or 값2 or 값3)
{ 필드: { $nin: [ 값1, 값2, 값3, ... ] } // 필드 != (값1 and 값2 and 값3)
// 조건1 or 조건2
{ $or: [ { 조건1 }, { 조건2 }, ... ] }
// 조건이 간단하면 그냥 { 필드: 값, 필드: 값 } 이렇게 $and가 없어도 되지만, 여러 논리연산자를 겹쳐 쓸 경우 $and가 필요합니다.
// (조건1 or 조건2) and (조건3 or 조건4)
{ $and: [
{ $or: [{ 조건1 }, { 조건2 }] },
{ $or: [{ 조건3 }, { 조건4 }] }
] }
// 조건1, 조건2 ... 모두 만족하지 않는 다큐먼트
{ $nor: [{ 조건1 }, { 조건2 }, ...] }
// 조건이 아닌값. $nor의 단일 버전
{ $not: { 조건 } }
// name이 Slime 그리고 hp가 25인 다큐먼트. 둘다 일치
db.monsters.find({
name: 'Slime',
hp: 25
}); // 하나의 객체에 두개의 키
// name이 Slime 또는 hp가 50.
db.monsters.find({
$or: [
{ name: 'Slime' },
{ hp: 50 }
]
}); // 배열에 두개의 객체
db.book.find({
"hits": {$gte:50}
})
// hits >= 50인 document를 조회한다.
db.book.find({
"hits": {$gt:40, $lt:70}
})
// hits가 40 초과 70 미만. 40 < hits < 70
db.book.find({
"name":{
$in:["A","B"]
}
}) // name이 A or B인 Document
db.book.find({
$or:[
{"name":"A"},
{"hits":50}
]
}) // name이 A 혹은 hits가 50인 Document
db.book.find({
$and:[
{"hits":{$lte:50}},
{"name":"B"}
]
}) // (hits < 50) and (name == B)인 Document
정규식 $regex
db.book.find({"name": {$regex: /a|b/, $options:"i"}})
db.book.find({"name": /a|b/i}).pretty()
// a또는 b 를 정규식으로 검색 option: i는 대소문자 무시
조건 $where
- 자바스크립트 문법을 사용해 검색할 수 있다
- this를 반드시 써줘야 인식 된다.
db.book.find({
$where: "this.name == 'A'"
})
// $where을 이용하면 자바스크립트 표현식(expression)을 사용할 수 있다.
// 다음 쿼리를 $where로 간단하게 표현 가능하다.
db.book.find({ $or: [ {name: 'A'}, {hits: {$lte: 50}} ] })
// ==
db.book.find({ $where: "this.name == 'A' || this.hits <= 50" })
정렬 sort
db.book.find()
.sort({"hits":1})
.pretty()
// hits를 오름차순으로 정렬해서 조회
// 1은 오름차순, -1은 내림차순
선택 필드 Projection
- projection이란 find와 findOne 메소드의 두 번째 인자로 넣어주는 것을 말한다.
- 결과로 보여줄 것만 필터링하는 기능을 가진다.
- projection이 유용한 경우는 민감한 데이터가 있을 경우다.
만약 댓글을 단 회원의 정보를 가져오고 싶은데 회원 정보를 통째로 가져오면 비밀번호나 개인 정보같은 게 모두 가져와지는데, 그럴 때 projection 객체를 사용해서 가져올 데이터만 걸러내는 것이다. - 또한 한 가지 더 장점은 용량이 줄어드는 것이다.
게시글 리스트에서 게시글들을 모두 불러오면 용량이 어마어마하다.
게시글 제목, 내용, 댓글까지 다 불러와지기 때문에, 이럴 때 제목만 불러오도록 하면 데이터를 아낄 수 있다.
db.book.find({}, {"_id":false, "name":true, "hits":true});
// 2번째 인자값은 option으로 보여질 Field에 대한 결정을 함
db.book.find( {$and:[{"name":"A"}]}, {"auther":{$slice:1}} )
// $slice를 하면 해당 갯수만큼의 Document만큼만 갖고온다.
이렇게 생각하면 간단하다.
기본적으로 몽고디비의 find( { 내용1 } ) 은 sql의 select * from 테이블 where 내용1 과 같다.
즉, find의 첫번째 객체인자는 where로 특정 다큐먼트를 골라 * 전체를 가져오는것이고
find( { 내용1 }, { 내용2 } ) 두번째 인자가 바로 select 내용2 from 테이블 where 내용1 과 같다고 보면 된다.
어떤걸 select해서 가져와서 민감한 데이터를 감출지 그 역할이다.
즉, 몽고디비는 SQL과는 달리 첫째 인자에 where이 오고 둘째 인자에 select 필드가 온다고 보면 된다.
데이터 수정 (update)
- 기본적으로 하나의 쿼리만 수정
- $set을 해야 해당 필드만 바뀐다.
만약 $set을 넣지 않고 그냥 { hp: 30 } 하면 다큐먼트의 내용이 다 지워지고 { hp: 30 } 이라는 객체로 통째로 바뀌어버린다. (통째로 대체)
db.book.update({
"hits":110
}, {
$set:{
"hits":120
}
})
// hits:110인걸 검색해서 120으로 업데이트 하라
// update 첫번째인자는 검색 쿼리 key/field, 두번째 인자는 업데이트 쿼리 {$set: {key:field}}
db.book.update({
"hits":120 // hits이 120인걸 찾아
}, {
$set: {
hits:125, // 125로 업데이트를 하며,
name:"AA" // 기존에 name이 없었는데 AA를 추가
}
})
db.book.update({
name:"F"
}, {
$set: {
name:"F",
hits:20
}
}, {
upsert:true // upsert : 값이 없을 경우 insert 시행.
// update + insert의 합성어
})
// 만약 수정할 대상이 없다면 보통의 경우는 아무것도 변하지 않고 종료된다.
// upsert옵션을 통해 삽입 할 수 있다.
db.book.update({
hits:{$lte:30} // hits <= 30
}, {
$set:{
bestseller:"N"
}
},{
multi:true
})
// update는 기본적으로 하나의 행만 업데이트
// 따라서 여러 행을 업데이트 할 경우 {multi:true}로 설정
db.book.update({
name:"F"
}, {
$push:{
category:"science" // $push를 이용하여 category라는 field에 science라는 배열을 추가
}
})
db.book.update({
name:"F"
}, {
$pull:{
category:"science" // $pull을 이용하여 science 배열 값 제거
}
})
UpdateOne / UpdateMany / ReplaceOne
- updateOne은 매칭되는 다큐먼트 중 첫 번째만 수정
- updateMany는 매칭되는 모든 다큐먼트를 수정. 기존의 {multi:true} 옵션이 두 메소드로 나누어졌다고 생각하면 된다.
- replaceOne 메소드는 다큐먼트를 통째로 다른 것으로 대체. $set을 안 썼을 때 상황과 유사.
db.monsters.updateOne({
name: 'Slime'
}, {
$set: {
hp: 25
}
});
FindAndModify
- update 메소드와는 달리 upsert(update + insert)과 remove까지 같이 수행. 한 행만 업데이트 한다.
- query - 대상을 찾는 법,
- update - 대상을 수정할 내용,
- new - 수정 이전의 다큐먼트를 반환할지, 수정 이후의 다큐먼트를 반환할 지 결정하는 부분. { new: true }를 넣으면 수정 이후의 다큐먼트를 반환
- 수정한 후에 수정된 결과를 다시 가져오고 싶다면 update 대신 findAndModify 메소드를 쓰는 게 좋음
db.monsters.findAndModify({
query: { name: 'Demon' },
update: { $set: { att: 150 } },
new: true
});
/*
1. query - name: 'Demon'인 것을
2. update - att: 150 로 내용을 수정
3. new : true - 수정 이후의 다큐먼트를 반환
*/
findAndModify 명령과 update 명령 이 둘의 차이점은 아래와 같다.
- 디폴트 옵션에서는 두 명령보두 하나의 문서만 변경할 수 있다.
하지만 update 명령은 multi 옵션을 true로 설정해서 여러 문서를 한번에 변경할 수 있다. - update 명령은 실제 어떤 문서를 변경할지 알 수없다. (매칭된 문서가 여러개일때)
하지만 findAndModify는 sort 옵션을 통해 특정 문서를 정렬해 첫 번째 문서만 변경할 수 있다. - update명령은 처리 결과를 반환하지만, findAndModify는 변경전 혹은 직후의 문서를 결과로 반환한다.
FindOneAndUpdate / FindOneAndReplace
- findAndModify는 update, upsert, remove를 모두 담당하는데, 이 기능을 쪼개서 하나의 역할만 전담하는 메소드 라 할 수있다.
- 역시나 findAndModify 처럼 수정 이전 또는 이후의 다큐먼트를 반환 받는데, 대신 new 옵션이 아니라 returnNewDocument로 이름이 바뀌었다.
db.monsters.findOneAndUpdate(
{ name: 'Demon' },
{ $set: { att: 150 } },
{ returnNewDocument: true }
);
데이터 삭제 (remove)
db.book.remove()
// 전체를 삭제
db.book.remove({"name":"def"})
// 해당 Document 리스트를 모두 삭제
DeleteOne, DeleteMany
- deleteOne은 매칭되는 첫 번째 다큐먼트만 지움
- deleteMany는 매칭되는 모든 다큐먼트를 지움
- remove 메소드를 세분화한 것이다.
db.monsters.deleteOne({ name: 'Zerp' });
remove를 deleteOne, deleteMany로 나눈 이유?
예를들어, 댓글 테이블에 삭제 버튼을 누르면 remove 된다고 하면
remove는 기본적으로 다중 삭제 처리라서, 나는 해당 댓글 하나만 삭제하려고 하나의 버튼을 눌렀는데 여러개가 지워질수있다는 위험성을 안고 있다.
물론 Object.id 를 통해 다른 다큐먼트와 관계를 맺어서 지우는거니, 당연히 중복(다중 처리)이 발생할리는 없겠지만, 만일 유니크하지않은 다른 필드로 검색했을때 다중으로 지워질수 있는 실수를 미연에 방지하고, 보다 개발자로 하여금 직관적으로 메서드를 행함을(하나만 처리해라, 여러개 처리해라) 표현하기 위해 api를 추가로 만들었다라고 이해하면 된다.
인용한 부분에 있어 만일 누락된 출처가 있다면 반드시 알려주시면 감사하겠습니다
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.