함께 성장하는 프로독학러
2. 검색하고자 하는 Document 를 조회하는 find() 메소드 본문
안녕하세요, 프로독학러 입니다.
이번 포스팅에서는 Document 를 검색하는 find() 메소드에 대해서 자세히 알아보도록 하겠습니다.
Document 를 조회하는 find() 메소드
find() 메소드의 표현식은 다음과 같습니다.
db.COLLECTION_NAME.find(query, projection)
find() 메소드의 인자로 query 와 projection 이 들어옵니다.
두 값 모드 Optional 파라메터입니다.
query 의 데이터 타입은 document(객체) 입니다. 이는 다큐먼트를 조회하는 기준을 정하는 파라메터입니다. 이 값이 생략되거나 비어있는 객체 {} 를 전달하면 해당 컬렉션의 모든 다큐먼트들을 조회합니다.
projection 의 데이터 타입 역시 document 로, 조회한 다큐먼트의 표시할 field 를 지정하는 것 입니다.
메소드의 리턴 값은 cursor 객체입니다. cursor 객체는 limit() 메소드, skip() 메소드, sort() 메소드 등을 가지고 있어 조회된 데이터를 핸들링 할 수 있습니다. cursor 객체의 메소드에 대해서는 다음 포스팅에서 알아보도록 하고, find() 메소드의 query 와 projection 에 대해서 자세히 알아봅시다.
*실습을 위해서 insert 콜렉션 안에 다음과 같이 document 들을 추가합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | db.articles.insert([ { "title": "article01", "content": "content01", "writer": "Velopert", "likes": 0, "comments": [] }, { "title": "article02", "content": "content02", "writer": "Alpha", "likes": 23, "comments": [ { "name": "Bravo", "message": "Hey Man!" } ] }, { "title": "article03", "content": "content03", "writer": "Bravo", "likes": 40, "comments": [ { "name": "Charlie", "message": "Hey Man!" }, { "name": "Delta", "message": "Hey Man!" } ] } ]) | cs |
BulkWriteResult 에 nInserted 값이 3으로, 3개의 다큐먼트가 정상적으로 articles 콜렉션에 추가된 것을 알 수 있다.
- query
query는 다큐먼트를 조회하는 기준을 지정하는 파라메터 입니다.
이를 생략하면 모든 데이터를 조회할 수 있죠.
db.articles.find()
articles 콜렉션 안에 있는 모든 다큐먼트들을 조회했습니다.
하지만 조회된 결과가 보기에 썩 좋지 않네요.
예쁘게 조회해 봅시다.
db.articles.find().pretty()
같은 결과지만 알아보기에 좀 더 편하게 줄바꿈과 간격조절이 되어 출력됩니다.
articles 의 다큐먼트 중 writer 가 Bravo 인 다큐먼트를 검색하려면 어떻게 하면 될까요?
다음과 같습니다.
db.articles.find({ "writer" : "Bravo" }).pretty()
특정 field 의 정확한 값으로 다큐먼트를 조회할 때는 find 의 query 로 찾을 document 를 객체 형식으로 지정해 주면됩니다.
만약 특정 field 의 정확한 값을 아는것이 아니라 비교나 정규표현식을 통해 다큐먼트를 조회하려면 어떻게 해야할까요?
Query 연산자
find() 메소드를 사용할 때 비교나 정규표현식 등을 사용할 때는 Query 연산자를 사용합니다.
Query 연산자의 종류는 비교(Comparison), 논리(Logical), 요소(Element), 배열(Array) 등이 있습니다.
이 이외에도 여러 종류의 Query 연산자가 있지만, 가장 자주 사용되는 것들에 대해서 알아보도록 하겠습니다.
*이외의 Query 연산자에 대해 궁금하신분은 MongoDB 메뉴얼을 참고해 주세요.
<MongoDB Query and Projection Operators>
*연산자는 객체 형태로 사용합니다.
- 비교(Comparison) 연산자
가장 먼저 살펴볼 연산자는 비교 연산자입니다. 이는 프로그램밍 언어에서 >, <, <=. ==, !, != 등과 같은 비교를 위한 연산자 입니다.
operator |
설명 |
$eq |
(equals) 주어진 값과 일치하는 값 |
$gt |
(greater than) 주어진 값보다 큰 값 |
$gte |
(greater than or equals) 주어진 값보다 크거나 같은 값 |
$lt |
(less than) 주어진 값보다 작은 값 |
$lte |
(less then or equals) 주어진 값보다 작거나 같은 값 |
$ne |
(not equlas) 주어진 값과 일치하지 않는 값 |
$in |
(in) 주어진 배열 안에 속하는 값 |
$nin |
(not in) 주어진 배열 안에 속하지 않는 값 |
articles 콜렉션 안의 다큐먼트 중 like 필드의 값이 10보다 크고 30보다 작은 다큐먼트를 조회하려면 어떻게 해야할까요?
db.articles.find( { "likes" : { $gt : 10, $lt : 30 } } ).pretty()
like 필드의 값이 23 인 다큐먼트가 조회되었습니다.
writer 필드의 값이 배열 ["Alpha", "Bravo"] 안에 속하는 값인 다큐먼트를 조회하려면 다음과 같이 명령어를 입력합니다.
db.articles.find( { "writer" : { $in : ["Alpha", "Bravo"] } } ).pretty()
- 논리(Logical) 연산자
논리 연산자의 종류는 다음과 같습니다.
*논리 연산자의 조건이 여러개 일 경우, 조건들을 배열안에 넣습니다.
Operator |
설명 |
$or |
주어진 조건 중 하나라도 만족한다면 true |
$and |
주어진 조건을 모두 만족해야만 true |
$not |
주어진 조건이 거짓일 때 true |
$nor |
주어진 모든 조건이 거짓일 때 true |
title 의 값이 "article01" 이거나 writer 의 값이 "Alpha" 인 도큐먼트를 조회하려면 다음과 같이 명령어를 입력합니다.
db.articles.find( { $or : [ { title : "article01" }, { writer : "Alpha" } ] } ).pretty()
writer 의 값이 "Alpha" 이고, like 의 값이 20 이상인 다큐먼트를 조회할 때는 다음과 같이 합니다.
db.articles.find( { $and : [ { writer : "Alpha" }, { likes : { $gt : 20 } } ] } ).pretty()
*$and 연산자는 하나의 query 객체로 표현하는 것과 같습니다.
db.articles.find( { $and : [ { writer : "Alpha" }, { likes : { $gt : 20 } } ] } ).pretty()
=
db.articles.find( { writer : "Alpha", likes : { $gt : 20 } } ).pretty()
- $regex 연산자
$regex 연산자를 통하여 Document 를 검색할 때 정규표현식을 이용할 수 있습니다.
$regex 연산자를 사용하는 방식은 아래의 네 가지 방법이 있습니다.
- { <field>: { $regex: /pattern/, $options: '<options>' } }
- { <field>: { $regex: 'pattern', $options: '<options>' } }
- { <field>: { $regex: /pattern/<options> } }
- { <field>: /pattern/<options> }
여기서 사용된 options 는 다음과 같습니다.
option |
설명 |
i |
대소문자를 무시하고 검색 |
m |
정규식에서 (^) 를 사용 할 때(시작부분 검색) 줄바꿈을 무력화 |
x |
정규식 안에 있는 공백을 모두 무시 |
s |
dot( . - any chracter) 사용시 줄바꿈을 포함해서 매치 |
만약 title 의 값이 정규표현식 article0[1-2] 를 만족하는 다큐먼트를 조회하려면 다음과 같이 명령어를 입력합니다.
db.articles.find( { title : /article0[1-2]/ } ).pretty()
*정규표현식에서 [ ] 는 문자 한 개를 의미, 대쉬(-) 는 ~에서 ~까지를 의미.
**[1-2] 1에서 2까지의 문자 한 개.
- $where 연산자
MongoDB 는 자바스크립트 기반이기 때문에 $where 연산자를 통하여 javascript expression 을 사용할 수 있습니다.
commnets 필드가 비어있는 다큐먼틀을 조회하려면 다음과 같이 명령어를 입력합니다.
db.articles.find( { $where : "this.comments.length === 0" } ).pretty()
*$where 연산자의 값은 문자열로 입력합니다. (문자열로 자바스크립트 표현식을 사용)
*this 는 article 안에 있는 document 들을 의미
- $elemMatch 연산자
$elemMatch 연산자는 도큐먼트 안에 있는 서브 도큐먼트(Embedded Document)들의 배열을 쿼리할 때 사용합니다.
우리가 사용하고 있는 예제에서는 comments 필드가 Embedded Document 를 포함하는 필드에 해당됩니다.
articles 의 도큐먼트 중 "Charlie" 가 작성한 덧글이 있는 도큐먼트를 조회하는 방법은 다음과 같습니다.
db.articles.find( { comments : { $elemMatch : { name : "Charlie" } } } ).pretty()
*Embedded Documents 의 필드 (여기서는 comments 필드) 의 값에 $elemMatch 연산자를 적용
*위의 예제는 Embedded Document 가 배열안에 도큐먼트로 존재하는 형식이었습니다. 만약 Embedded Document 가 배열 안에 도큐먼트가 있는 형식이 아니라면 다음과 같이 처리합니다.
db.users.insert({
"username": "velopert",
"name": { "first": "M.J.", "last": "K."},
"language": ["korean", "english", "chinese"]
})
위의 코드와 같이 users 콜렉션에 도큐먼트를 하나 추가해 봅시다.
추가된 도큐먼트의 name 필드의 값은 도큐먼트 하나 입니다.(Embedded Document)
그리고 language 필드의 값은 배열인데, 배열의 원소들은 도큐먼트형식이 아닌 문자열 입니다.
이 도큐먼트에서 name 필드의 값인 도큐먼트의 first 의 값이 "M.J." 인 도큐먼트를 검색하려면 다음과 같이 합니다.
db.users.find({ "name.first" : "M.J."})
language 필드의 값의 배열 중 원소가 "korean" 인 도큐먼트를 검색할 때는 다음과 같이 합니다.
db.users.find({ "language" : "korean"})
- projection
이제 find() 메소드의 두 번째 파라메터인 projection 에 대해서 알아보도록 하겠습니다.
projection 은 query 의 결과 값을 보여줄 때 표시할 필드를 지정하는 것입니다.
projection 역시 document 형식으로 지정하며, document 안의 key 와 value 의 값은 각각 필드명, 표시여부(Boolean) 입니다.
articles 컬렉션의 모든 다큐먼트를 검색할 때 title 과 content 필드만을 보이고 싶다(projection)면 다음과 같이 합니다.
db.articles.find( {}, { _id : false, title : true, content : true } )
*projection 시 _id 필드를 제외한 모든 필드들은 기본값이 false 이다. _id 는 기본값이 true 이므로 _id 필드를 프로젝션하지 않으려면 _id 필드를 false 로 지정해 주어야 한다.
- $slice 연산자
projection 의 $slice 연산자는 Embeded Document 배열을 불러올 때 갯수를 제한하는 역할을 합니다.
title 이 "article03" 인 도큐먼트의 덧글을 1개만 보이도록 조회
db.articles.find( { title : "article03" }, { comments : { $slice : 1 } } )
*원래 title 이 "article03" 인 도큐먼트의 덧글은 2개 이지만 projection 을 통해 한개만 보여지도록 제한 한 것.
- $elemMatch 연산자
projectoin 의 $elemMatch 는 query 의 $elemMatch 와 사용법이 같습니다.
하지만 하는 역할은 약간 다릅니다.
query 의 $elemMatch 는 $elemMatch 연산자를 통해 해당 조건을 만족하는 Embeded Document 가 있는 도큐먼트를 조회하는 것입니다.
즉, $elemMatch 의 조건을 만족하는 Document 의 모든 Embeded Document 들을 보여주는 것이죠.
반면 projectoin 의 $elemMatch 는 해당 $elemMatch 연산자의 조건을 만족하는 Embeded Document 만을 출력합니다.
db.articles.find(
{
"comments": {
$elemMatch: { "name": "Charlie" }
}
},
{
"title": true,
"comments.name": true,
"comments.message": true
}
).pretty()
위의 명령의 결과는 다음과 같습니다.
comments 의 필드의 모든 Embeded Document 를 출력하죠.
db.articles.find(
{
"comments": {
$elemMatch: { "name": "Charlie" }
}
},
{
"title": true,
"comments": {
$elemMatch: { "name": "Charlie" }
},
"comments.name": true,
"comments.message": true
}
).pretty()
위의 명령은 projection 객체에 comments 필드에 $elemMatch 연산자를 사용하고 있습니다.
결과는 다음 그림과 같습니다.
이전의 코드와 달리 projection document의 comments 필드에 $elemMatch 을 적용하여, writer 필드 값이 Charile 인 Embedded Documnet 만을 프로젝션 했습니다.
여기까지
특정 콜렉션 안에 있는 도큐먼트를 조회하는 메소드인 find() 메소드에 대해서 알아보았습니다.
find() 메소드의 인자는 두 가지가 올 수 있는데, 첫 번째 인자는 query 로 조회할 도큐먼트의 조건을 지정하는 것입니다. query 에서는 다양한 연산자들을 사용하여 도큐먼트를 검색할 수 있습니다. 두 번째 인자는 projection 으로 query 의 조건으로 조회된 다큐먼트의 어떤 필드를 출력하고 출력하지 않을지 지정하는 것입니다.
포스팅의 첫 부분에서 언급한 바와 같이 find() 메소드의 리턴값은 cursor 객체 입니다. 이 cursor 객체는 조회된 다큐먼트들의 객체로 sort(), limit(), skip() 등의 메소드를 가지고 있습니다.
다음 포스팅에서는 이 메소드 들에 대해서 자세히 알아보도록 하겠습니다.
감사합니다.
**참고 자료 (항상 감사드립니다)
*이 포스팅이 도움이 되셨다면 다녀가셨다는 표시로 공감 부탁드릴게요! (로그인 하지 않으셔도 공감은 가능합니다 ㅎㅎ)
'Programming > MongoDB' 카테고리의 다른 글
4. Document 를 수정, update() 메소드 (0) | 2018.05.06 |
---|---|
3. find() 의 결과를 활용, sort(), limit(), skip() (1) | 2018.05.06 |
1. MongoDB 데이터 모델링, DB/Collection/Document 생성 및 제거 (0) | 2018.05.05 |
0. MongoDB 소개, 설치 및 실행 (0) | 2018.05.04 |