샘플 데이터

  • "맛있는 MongoDB"
    • 샘플 데이터 공유
$ git clone https://github.com/Karoid/mongodb_tutorials.git
$ ec2-user@mongodb:~$ cd mongodb_tutorials/car_accident/

ec2-user@mongodb:~/mongodb_tutorials/car_accident$ mongoimport -d car_accident -c area --file area.json
2021-03-02T13:29:00.380+0000    connected to: localhost
2021-03-02T13:29:00.403+0000    imported 228 documents
ec2-user@mongodb:~/mongodb_tutorials/car_accident$
ec2-user@mongodb:~/mongodb_tutorials/car_accident$ mongoimport -d car_accident -c by_month --file by_month.json
2021-03-02T13:29:32.252+0000    connected to: localhost
2021-03-02T13:29:32.309+0000    imported 227 documents
ec2-user@mongodb:~/mongodb_tutorials/car_accident$
ec2-user@mongodb:~/mongodb_tutorials/car_accident$ mongoimport -d car_accident -c by_road_type --file by_road_type.json
2021-03-02T13:29:50.266+0000    connected to: localhost
2021-03-02T13:29:50.309+0000    imported 227 documents
ec2-user@mongodb:~/mongodb_tutorials/car_accident$
ec2-user@mongodb:~/mongodb_tutorials/car_accident$ mongoimport -d car_accident -c by_type --file by_type.json
2021-03-02T13:30:08.372+0000    connected to: localhost
2021-03-02T13:30:08.408+0000    imported 687 documents

> show dbs
admin        0.000GB
car_accident  0.000GB
config        0.000GB
local        0.000GB
test          0.000GB
>
> use car_accident
switched to db car_accident
> show tables
area
by_month
by_road_type
by_type

 

  • Find 관련 명령어에는 여러 개가 있으며, 그 중에 많이 사용하는 위주로 가이드 하며, 필요 시 추가 가이드 진행 예정

명령어

내역

find()

검색

findAndModify()

검색 후 수정

Update, upset, remove 모두 가능

new : true를 설정하여 update 이후 값을 리턴

new : false 또는 미적용 시 update 이전 값을 리턴

 

db.monsters.findAndModify({

    query: { name: "Dragon" },

    update: { $inc: { att: 1000 } ,$set :{"name":"Dragon","hp":4000,"att":1000}},

    upsert: true,

    new : true

})

findOne()

한건만 검색

findOneAndDelete()

한건만 검색 후 삭제

findOneAndReplace() > v3.2

한건만 검색 후 변경

returnNewDocument : true 설정하여 변경 전후 확인 가능

Replace 와 Update의 경우 Update는 명시한 필드만 변경 되지만, Replace의 경우는 명시한 필드 변경 외에는 나머지 필드는 모두 삭제 됨

가급적이면 Update만 사용 해야함

findOneAndUpdate()  > v3.2

한건만 검색 후 변경

returnNewDocument : true 설정하여 변경 전후 확인 가능

 

[Find]

  • Find명령어 사용 시 필요한 filed 명을 사용하여 검색하시기 바랍니다.(Covered Query)
  • Ex) db.bios.find( {조건}, {_id:0, name:1 , money:1})
    • 쿼리가 요구하는(리턴되는) 내용의 모든 필드가 하나의 Index에 포함되어 있으므로, Index만 조회하기 때문에 Document를 조회하는 것보다 훨씬 빠름(일반적으로 인덱스 키는 RAM에 적재되 있거나 디스크에 순차적으로 위치 하기 때문)
    • _id 필드를 0으로 명시하지 않는 경우, 결과 값에서 표현이 되기 때문에, covered query 조건이 되지 않으므로, 반드시 _id 필드를 0으로  명시
    • 쿼리에 필드가 없거나 필드의 값이 null 이 되면 안된다. i.e. {"field" : null} or {"field" : {$eq : null}}
    • v3.6 부터 embedded document의 경우도 적용 (이전 버전 에서는 불가능?)
      • db.userdata.find( { "user.login": "tester" }, { "user.login": 1, _id: 0 } )
      • 테스트 결과 안되요ㅠ(알고 계신 분 알려주세요)
    • 제한
      • Geospatial Index 에서는 사용 못함
      • Multikey Index에서 배열 필드에 대해서는 Covered index 가 불가능(v3.6부터 non-array field들에 대해서는 사용 가능)
    • Covered Query
  • field 명시 방법
    • 필드에 _id 여부는 항상 명시해야 함(_id를 쿼리 결과 내에서 표현하거나 표현하지 않는 것에 대해 명시를 반드시 해야 함)
    • _id에 대해서만 혼용 사용 가능하며, 다른 필드들에 대해서는 보여 주고 싶은 것에 대해서만 1로 명시, 0으로 명시하면 에러 발생
    • Ex ) > db.thing.find( { }, {_id:0, empno: 1} )  // empno만 표시하고, _id 및 다른 필드는 표시 안함. // 여기서 중요한건 _id는 항상 명시해 줘야 하며, 보고 싶은 필드만 1로 설정해서 표시 // 다른 필드의 경우 birth 필드가 있더라도 birth:0 으로 하면 에러 발생...왜???모르겠음
    • 만약 empno만 빼고 다 보고자 하면 그때는 > db.thing.find( { }, {empno: 0} ) 이런 식으로 표시
    • 보고 싶은 field가 있다면, field를 명시할 때 보겠다는 field 들만 명시를 하고,field 명시 여부를 혼용해서 명시하게 되면, 에러가 발생
    • 반대로 보고 싶지 않은 field가 있다면 명시 안하겠다는 field 들만 명시를 해야 함

[Filed] 

  • Covered Query Test
# semester 에 대한 Index 확인
> db.employee.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "semester" : 1
                },
                "name" : "semester_1"
        }
]

# _id 필드를 명시적으로 0 처리 하지 않으면, 자연스럽게 _id 필드도 같이 표시되기 때문에 명시적으로 _id 필드를 표시 안한다고 해야, Convered query 적용 여부를 확인 가능
> db.employee.find({semester:3},{_id:0, semester:1}).explain()

# 필드를 표시 안하게 되는 경우 _id 필드가 표현 되기에 covered query가 되지 않음
> db.employee.find({semester:3},{"field" : null}).explain()

#  covered index 확인

# 필드를 표시 안 하게 되는 경우 _id 필드가 표현 되기에 covered query가 되지 않음 (단순 인덱스 스캔 - fetch 진행)

#실패 - embedded Document 에 대한 covered query 실패
> db.inventory.insertMany( [
    { item: "journal", instock: [ { warehouse: "A", qty: 5 }, { warehouse: "C", qty: 15 } ] },
    { item: "notebook", instock: [ { warehouse: "C", qty: 5 } ] },
    { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 15 } ] },
    { item: "planner", instock: [ { warehouse: "A", qty: 40 }, { warehouse: "B", qty: 5 } ] },
    { item: "postcard", instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] }
]);
{
        "acknowledged" : true,
        "insertedIds" : [
                ObjectId("603cf504850313ab26e27ced"),
                ObjectId("603cf504850313ab26e27cee"),
                ObjectId("603cf504850313ab26e27cef"),
                ObjectId("603cf504850313ab26e27cf0"),
                ObjectId("603cf504850313ab26e27cf1")
        ]
}
>
> db.inventory.createIndex({item:1, "instock.qty":1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
# 데이터 확인
> db.inventory.find({item:"journal", "instock.qty":5}, {_id:0,item:1, "instock.qty":1})
{ "item" : "journal", "instock" : [ { "qty" : 5 }, { "qty" : 15 } ] }

# covered 체크
> db.inventory.find({item:"journal", "instock.qty":5}, {_id:0,item:1, "instock.qty":1}).explain()

# 단일로 진행 실패
> db.inventory.insertOne({ item: "test_item", instock: [{warehouse: "A", qty: 5}]})
> db.inventory.find({item:"test_item", "instock.qty":5}, {_id:0,item:1, "instock.qty":1}).explain()

# 단일로 진행 실패 2
> db.inventory.insertOne({ item: "test_item_2", instock: [{qty: 5}]})
> db.inventory.find({item:"test_item_2", "instock.qty":5}, {_id:0,item:1, "instock.qty":1}).explain()

비교(Comparison) 연산자

operator

설명

 

$eq

(equals) 주어진 값과 일치하는 값

find({ 대상필드:{원하는연산자:조건값}})

 

 

 

 

 

$gt

(greater than) 주어진 값보다 큰 값

$gte

(greather than or equals) 주어진 값보다 크거나 같은 값

$lt

(less than) 주어진 값보다 작은 값

$lte

(less than or equals) 주어진 값보다 작거나 같은 값

$ne

(not equal) 주어진 값과 일치하지 않는 값

$in

주어진 배열 안에 속하는 값

반드시 배열 형태로 질의

find({필드:{$in / $nin :[ { 원하는값 A } , { 원하는값 B } ] } })

$nin

주어진 배열 안에 속하지 않는 값

논리 연산자

operator

설명

 

$or

주어진 조건중 하나라도 true 일 때 true

배열 형태로 질의 진행

find({$or / $and / $not / $nor : [{조건A},{조건B}]})

$and

주어진 모든 조건이 true 일 때 true

$not

주어진 조건이 false 일 때 true

$nor

주어진 모든 조건이 false 일때 true

> db.inventory.find({"instock.qty":{$eq:5}})
{ "_id" : ObjectId("603cf504850313ab26e27ced"), "item" : "journal", "instock" : [ { "warehouse" : "A", "qty" : 5 }, { "warehouse" : "C", "qty" : 15 } ] }
{ "_id" : ObjectId("603cf504850313ab26e27cee"), "item" : "notebook", "instock" : [ { "warehouse" : "C", "qty" : 5 } ] }
{ "_id" : ObjectId("603cf504850313ab26e27cf0"), "item" : "planner", "instock" : [ { "warehouse" : "A", "qty" : 40 }, { "warehouse" : "B", "qty" : 5 } ] }
{ "_id" : ObjectId("603cf675850313ab26e27cf2"), "item" : "test_item", "instock" : [ { "warehouse" : "A", "qty" : 5 } ] }
{ "_id" : ObjectId("603cf6d7850313ab26e27cf3"), "item" : "test_item_2", "instock" : [ { "qty" : 5 } ] }

# county 가 종로구,중구 또는 population 이 3,552,490 보다 큰 경우
> db.area.find({$or:[{county: "종로구"},{county:"중구"},{population:{$gte:3552490}}]})

{ "_id" : ObjectId("5c88f9f70da47a8507752775"), "city_or_province" : "서울", "county" : "종로구", "population" : 152737 }
{ "_id" : ObjectId("5c88f9f70da47a8507752776"), "city_or_province" : "서울", "county" : "중구", "population" : 125249 }
{ "_id" : ObjectId("5c88f9f70da47a850775278e"), "city_or_province" : "부산", "county" : "중구", "population" : 45208 }
{ "_id" : ObjectId("5c88f9f70da47a8507752830"), "city_or_province" : "대구", "county" : "중구", "population" : 79712 }
{ "_id" : ObjectId("5c88f9f70da47a850775283f"), "city_or_province" : "인천", "county" : "중구", "population" : 115249 }
{ "_id" : ObjectId("5c88f9f70da47a8507752848"), "city_or_province" : "대전", "county" : "중구", "population" : 252490 }
{ "_id" : ObjectId("5c88f9f70da47a850775284c"), "city_or_province" : "울산", "county" : "중구", "population" : 242536 }

# county 가 종로구,중구 가운데, population 이 125,249 보다 큰 경우 (and / or 연산이 공존)
> db.area.find({$and:[{$or:[{county: "종로구"},{county:"중구"}]},{population:{$gte:125249}}] })

{ "_id" : ObjectId("5c88f9f70da47a8507752775"), "city_or_province" : "서울", "county" : "종로구", "population" : 152737 }
{ "_id" : ObjectId("5c88f9f70da47a8507752776"), "city_or_province" : "서울", "county" : "중구", "population" : 125249 }
{ "_id" : ObjectId("5c88f9f70da47a8507752848"), "city_or_province" : "대전", "county" : "중구", "population" : 252490 }
{ "_id" : ObjectId("5c88f9f70da47a850775284c"), "city_or_province" : "울산", "county" : "중구", "population" : 242536 }

# county 가 종로구,중구 가운데, population 이 125,249 보다 큰 경우 ($and / $in 연산이 공존)
> db.area.find({$and:[{county:{$in:["종로구","중구"]}}, {population:{$gte:125249}}] })

{ "_id" : ObjectId("5c88f9f70da47a8507752775"), "city_or_province" : "서울", "county" : "종로구", "population" : 152737 }
{ "_id" : ObjectId("5c88f9f70da47a8507752776"), "city_or_province" : "서울", "county" : "중구", "population" : 125249 }
{ "_id" : ObjectId("5c88f9f70da47a8507752848"), "city_or_province" : "대전", "county" : "중구", "population" : 252490 }
{ "_id" : ObjectId("5c88f9f70da47a850775284c"), "city_or_province" : "울산", "county" : "중구", "population" : 242536 }

$regex 연산자

  • $regex 연산자(정규표현식)를 이용하여, Document를  찾을 수 있음
{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ <field>: { $regex: 'pattern', $options: '<options>' } }
{ <field>: { $regex: /pattern/<options> } }
{ <field>: /pattern/<options> }
  • 4번쨰 라인 처럼 $regex 를 작성하지 않고 바로 정규식을 쓸 수도 있으며,  $options 정보 를 이용도 가능

option

설명

i

대소문자 무시

m

정규식에서 anchor(^) 를 사용 할 때 값에 \n 이 있다면 무력화

x

정규식 안에있는 whitespace를 모두 무시

s

dot (.) 사용 할 떄 \n 을 포함해서 매치

  • 정규식 test_item_[1-2] 에 일치하는 값이 item 조회
    • 조회하는 데이터의 "" 사용 안함.
> db.inventory.find({item : /test_item_[1-2]/})
{ "_id" : ObjectId("603cf6d7850313ab26e27cf3"), "item" : "test_item_2", "instock" : [ { "qty" : 5 } ] }

#대소문자 무시 i 옵션 이용
> db.inventory.find({item : /Test_item_[1-2]/i})
{ "_id" : ObjectId("603cf6d7850313ab26e27cf3"), "item" : "test_item_2", "instock" : [ { "qty" : 5 } ] }

$text 연산자

  • Text 검색으로 단어 형태만 검색이 가능 (띄어쓰기 단위 -> 가령 한 단어 내에 포함된 것은 검색이 안됨)
  • 대 소문자 구분 안함
  • 각 나라별 언어에 맞춰 검색이 지원되고 있지만, 한글은 지원되지 않음.
  • 문자열 인덱스를 만들어야 사용 가능
    • 해당 Collection 의 텍스트 인덱스 안에서만 작동하기 때문

필드

설명

$search

검색하려는 내용을 담는다. 구절로 설정되지 않으면 띄어 쓴 단어를 포함한 모든 Document반환

$language

Option. 검색하는 언어를 설정

MongoDB가 지원하는 언어를 설정할 수 있으며, 설정되지 않으면 인덱스에 설정된 내용을 따름

$caseSensitive

Option. Bollean 값.

문자의 대,소문자 구분을 결정하며, Default는 구분하지 않음(False)

$diacriticSensitive

Option. Bollean 값.

e`와 e 와 같이 알파벳의 위아래에 붙이는 기호를 무시할지를 정함. Default로는 false (무시 하지 않음)

> db.inventory.createIndex({ item:"text" })

> db.inventory.find( {$text:{$search:"test"}} )
{ "_id" : ObjectId("603e498748883f8cbbc18bd9"), "item" : "keep Test" }
{ "_id" : ObjectId("603e47f148883f8cbbc18bd7"), "item" : "keep test" }
{ "_id" : ObjectId("603e47e248883f8cbbc18bd6"), "item" : "test keep" }

  • 문자열 내 test 를 검색하는데, test_item 같은 것은 검색이 안됨. keep test / test keep 같이 띄어쓰기 된 것에 대해서만 검색

$where 연산자

  • $where 연산자를 통하여 javascript expression 을 사용 가능
#comments field 가 비어있는 Document 조회

> db.articles.find( { $where: "this.comments.length == 0" } )
{ "_id" : ObjectId("56c0ab6c639be5292edab0c4"), "title" : "article01", "content" : "content01", "writer" : "Velopert", "likes" : 0, "comments" : [ ]

 

$elemMatch 연산자

  • $elemMatch 연산자는 Embedded Documents 배열을 쿼리할때 사용
# comments 중 "Charlie" 가 작성한 덧글이 있는 Document 조회를 했을때, 게시물 제목과 Charlie의 덧글부분만 읽고싶은 경우
# 이렇게 해보면 의도와는 다르게  Delta 의 덧글도 출력
> db.articles.find(
    {
        "comments": {
            $elemMatch: { "name": "Charlie" }
        }
    },
    {
        "title": true,
        "comments.name": true,
        "comments.message": true
    }
)
{
        "_id" : ObjectId("56c0ab6c639be5292edab0c6"),
        "title" : "article03",
        "comments" : [
                {
                        "name" : "Charlie",
                        "message" : "Hey Man!"
                },
                {
                        "name" : "Delta",
                        "message" : "Hey Man!"
                }
        ]
}

 

  • Embedded Document 배열이 아니라 아래 Document의 "name" 처럼 한개의 Embedded Document 경우
> db.users.find({
    "username": "velopert",
    "name": { "first": "M.J.", "last": "K."},
    "language": ["korean", "english", "chinese"]
  }
)
> db.users.find({ "name.first": "M.J."})
  • Document의 배열이아니라 그냥 배열일 시에는 다음과 같이 Query
> db.users.find({ "language": "korean"})

projection

  • find() 메소드의 두번째 parameter 인 projection
  • 쿼리의 결과값에서 보여질 field를 정할 대 사용
# article의 title과 content 만 조회

> db.articles.find( { } , { "_id": false, "title": true, "content": true } )
{ "title" : "article01", "content" : "content01" }
{ "title" : "article02", "content" : "content02" }
{ "title" : "article03", "content" : "content03" }

$slice 연산자

  • projector 연산자 중 $slice 연산자는 Embedded Document 배열을 읽을때 limit 설정
# title 값이 article03 인 Document 에서 덧글은 하나만 보이게 출력
$slice 가 없었더라면, 2개를 읽어와야하지만 1개로 제한을 두었기에 한개만 출력

> db.articles.find({"title": "article03"}, {comments: {$slice: 1}}).pretty()
{
        "_id" : ObjectId("56c0ab6c639be5292edab0c6"),
        "title" : "article03",
        "content" : "content03",
        "writer" : "Bravo",
        "likes" : 40,
        "comments" : [
                {
                        "name" : "Charlie",
                        "message" : "Hey Man!"
                }
        ]
}

 

 

$elemMatch

  • 위의 elemMatch 는 조건 연산자에서 사용하는 것이며,
  • 해당 elemMatch 는 필드 내, 즉 projection 파라메터 입니다.
# $elemMatch 연산자를 projection 연산자로 사용하면 이를 구현 가능
# comments 중 "Charlie" 가 작성한 덧글이 있는 Document 중 제목, 그리고 Charlie의 덧글만 조회 (필드 선언 시 다시 한번 더 eleMatch를 진행하게 되면 Delta 의 댓글은 안보임
> db.articles.find(
...     {
...         "comments": {
...             $elemMatch: { "name": "Charlie" }
...         }
...     },
...     {
...         "title": true,
...         "comments": {
...             $elemMatch: { "name": "Charlie" }
...         },
...         "comments.name": true,
...         "comments.message": true
...     }
... )
{ "_id" : ObjectId("56c0ab6c639be5292edab0c6"), "title" : "article03", "comments" : [ { "name" : "Charlie", "message" : "Hey Man!" } ] }

 

[findAndModify]

  • Single Document 에 대한 수정하고 반환
  • 반환 된 Document는 수정에 대한 결과가 아님
  • 반환 된 Document 에 수정한 내역을 확인하고 싶으면 new Option을 이용
    • new 옵션을 true로 하는 경우 변경 후의 결과 값을 보여주며, Default 로 new 옵션을(false) 선언하지 않는 경우 변경 되기 전 값을 출력
# mosters 에서 name이 'Demon' 의 att를 350으로 변경하고 변경한 후 결과 확인
> db.monsters.findAndModify({ query: { name: 'Demon' }, update: { $set: { att: 350 } }, new: true })

db.collection.findAndModify({
    query: <document>,
    sort: <document>,
    remove: <boolean>,
    update: <document or aggregation pipeline>, // Changed in MongoDB 4.2
    new: <boolean>,
    fields: <document>,
    upsert: <boolean>,
    bypassDocumentValidation: <boolean>,
    writeConcern: <document>,
    collation: <document>,
    arrayFilters: [ <filterdocument1>, ... ]
});

> db.monsters.findAndModify({
    query: { name: "Dragon" },
    update: { $inc: { "att": 1000 } ,$set :{"name":"Dragon","hp":4000,"att":1000}},
    upsert: true,
    new : true
})

> db.monsters.findAndModify({
    query: { name: "Dragon" },
    update: {$set :{"hp":2000,"att":2000}},
    upsert: true,
    new : true
})

> db.monsters.findAndModify({
    query: { name: "Dragon" },
    update: {$set :{"hp":3000,"att":2000}},
    upsert: true
})

# upsert / new
> db.monsters.find( {query:{ name: "Dragon_Baby" }} )
> db.monsters.findAndModify({
    query: { name: "Dragon_Baby" },
    update: {$set :{"hp":1000,"att":500}},
    upsert: true,
    new : true
})

# remove
> db.monsters.findAndModify({
    query: { name: "Dragon_Baby" },
    remove: true
})

# 여러개일 경우
> db.monsters.findAndModify({
    query: { name: "Dragon" },
    update: {$set :{"hp":4000,"att":5000}},
    upsert: true
})
  • new Option : true

  • upsert: true / new : true

  • remove : true
    • new:true
      • return 이 없기 때문에 에러
    • update : {xxxx}
      • 당연히 remove 되는데 update 에러 진행
    • remove 가 정상적으로 진행 시
      • 진행 이전 데이터 return  후 삭제

 

  • 여러 개일 경우
    • 역시 한 건만 변경 (update 처럼)

참고 : https://velopert.com/479

 

 

Cursor

 

반응형
  • 알면 유용한 것에 대한 고민 끝에 Cursor 에 대해 알아 두면 좋지 않을까 하여 공유 드립니다.

Cursor

Name

Description

memo

cursor.addOption()

쿼리 동작을 수정하는 특별한 protocol flag 를 추가

 

cursor.allowDiskUse()

Sort 명령어를 사용하여, 쿼리 결과 정렬 작업을 처리하는 동안, 100 Mb 메모리를 초과하여 Disk Temporary files를 사용한 내역

--------------------------------------------------------------------------------

MongoDB의 Aggregate() 명령은 기본적으로 정렬을 위해서 100mb 메모리까지 사용 가능.

만약 그 이상의 데이터를 정렬해야 하는 경우라면 Aggregate() 명령은 실패-> 이 때 allowDiskUse 옵션을 true로 설정 시 Aggregate()처리가 디스크를 이용해 정렬 가능. 이 때 MongoDB 데이터 Directory 하의에 "_temp"  Diretory 를 만들어 임시 가공용 데이터 파일을 저장

Real MongoDB-702p 참고

 

$ db.user_scores.aggregate([

{$match:{score:{$gt:50}}},

{$group:{_id:"$name",avg:{$avg:"$score"}}}

],{allowDiskUse:True})

cursor.allowPartialResults()

find 명령어를 사용하여 샤딩된 collection의 작업을 진행 중 오류로 인해 조회를 못하게 되는 경우, 부분적인 결과만 이라도 조회

 

cursor.batchSize()

Single network 메시지에서, MongoDB에서 Client로 결과를 내보낸 document 수

 

cursor.close()

cursor close. (리소스까지 비움)

 

cursor.isClosed()

리턴이 성공하면 cursor를 close

 

cursor.collation()

find()에 의해 리턴된 커서의 collection 을 지정

 

cursor.comment()

system.profile Collection에서 로그 및 시스템에서 실행한 쿼리를 추적하기 위해 쿼리에 설명 추가(주석)

 

cursor.count()

커서에서 결과 Document의 count

 

cursor.explain()

커서에서 쿼리 실행결과 보고

 

cursor.forEach()

커서에서 모든 Document에 대한 JavaScript 함수를 적용

 

cursor.hasNext()

Cursor 내 반환할 Document가 존재하면 True 를 리턴

 

cursor.hint()

쿼리에 특정 인덱스를 사용

 

cursor.isExhausted()

커서가 닫혀 있고, 배치에 남아있는 Document가 없는 경우 true를 반환

 

cursor.itcount()

커서 내 클라이언트로 제공할 Document의 수를 계산 (find().count()와 유사하지만, cursor에서 사용하는 영역?)

 

cursor.limit()

cursor document 결과 를 제한

 

cursor.map()

커서 결과 Document를 함수에 적용하고, 그 결과 값을 배열(Array) 형태로 저장

db.users.find().map( function(u) { return u.name; } );

-> forEach와 유사

cursor.max()

find 필드 값에 대한 max 값을 지정. cursor.hint()와 함께 사용

 

cursor.maxTimeMS()

cursor 작업의 누적 시간 제한 (ms)

 

cursor.min()

find 필드 값에 대한 min 값을 지정. cursor.hint()와 함께 사용

 

cursor.next()

cursor 내에서 다음 Document 를 반환

 

cursor.noCursorTimeout()

cursor 자동 닫힘의 Timeout 을 비활성화

 

cursor.objsLeftInBatch()

현재 cursor 내 남아있는 document 수를 반환

 

cursor.pretty()

cursor 결과를 읽기 쉽게 표시

 

cursor.readConcern()

find() 명령어에 대한 readConcern 을 지정

 

cursor.readPref()

레플리카셋에서 클라이언트가 다이렉트로 읽을 수 있도록 cursor 설정

 

cursor.returnKey()

Document가 아닌 인덱스 key를 반환하도록 커서를 수정

 

cursor.showRecordId()

결과 Document 에 내부 엔진 ID 필드를 추가

 

cursor.size()

skip()와 limit() 를 적용한 커서내 결과 Document count 를 리턴

 

cursor.skip()

커서 내 Document에서 skip 또는 패스한 후의 결과를 리턴

 

cursor.sort()

정렬값에 의해 정렬된 결과를 리턴

 

cursor.tailable()

capped collection에서 커서에 tail 하여 제공 (마지막 내역만 계속 공유?)

 

cursor.toArray()

커서에 의해 반환된 Document를 배열로 반환

 

cursor.forEach()

  • 예전 검색해서 저장해 놓은 쿼리
db.getCollectionNames().forEach(function(collection) {
  indexes = db[collection].getIndexes();
  print("Indexes for " + collection + ":");
  printjson(indexes);
});

cursor.itcount()

> db.SentMessages.find({Type : 'Foo'})
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19dd9834184ad6d3675c"), "Name" : "789", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19d29834184ad6d3675b"), "Name" : "456", "Type" : "Foo" }

> db.SentMessages.find({Type : 'Foo'}).count()
3

> db.SentMessages.find({Type : 'Foo'}).limit(1)
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }

> db.SentMessages.find({Type : 'Foo'}).limit(1).count();
3

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ])
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19dd9834184ad6d3675c"), "Name" : "789", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19d29834184ad6d3675b"), "Name" : "456", "Type" : "Foo" }

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ]).count()
2014-08-12T14:47:12.488+0100 TypeError: Object #<Object> has no method 'count'

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ]).itcount()
3

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ])
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ]).itcount()
1

> exit
bye

 

batchSize 와 Limit 비교

  • 참고(복붙이나 다름 없습니다.) : https://emflant.tistory.com/12
  • batchSize : 한 batch 당 가져오는 document 갯수.
  • limit : 쿼리의 결과로 가져올 총 갯수.
  • limit 와 batchSize 를 지정하지 않는 경우 batch는 한번 당 101개의 Document 결과를 리턴 하지만, Document 당 너무 많은 데이터가 있는 경우 batch 한번 당 1Mb 가 최대 size
  • limit 와 batchSize 를 지정하는 경우, 지정한 수만큼 리턴
    • 큰 수로 셋팅하더라도 4Mb 이상의 데이터를 한번의 Batch로 가져올 수 없음.
    • 인덱스 없이 데이터를 sort하는 경우 첫 번째  batch에 모든 데이터를 가져오지만, 최대 4 Mb 초과할 수 없음.
> // for문을 돌려서 간단한 데이터로 200개 document 를 등록한다.
> for (var i = 0; i < 200; i++) { db.foo.insert({i: i}); }
> var cursor = db.foo.find()
> // batchSize나 limit 값 지정없이 find 했으므로 기본 batch 크기인 101 documents
> cursor.objsLeftInBatch()
101

> // 한번에 모든 document들을 가져오기 위해 큰 limit 값을 셋팅하면 batchSize는 모든 document 수가 된다.
> var cursor = db.foo.find().limit(1000)
> cursor.objsLeftInBatch()
200

> // batchSize 가 limit 크기보다 작으면 batchSize가 우선한다.
> var cursor = db.foo.find().batchSize(10).limit(1000)
> cursor.objsLeftInBatch()
10

> // limit 가 batchSize 보다 작으면 limit 가 우선한다.
> var cursor = db.foo.find().batchSize(10).limit(5)
> cursor.objsLeftInBatch()
5

> // 각각 1MB 데이터로 10개의 document 를 등록한다.
> var megabyte = '';
> for (var i = 0; i < 1024 * 1024; i++) { megabyte += 'a'; }
> for (var i = 0; i < 10; i++) { db.bar.insert({s:megabyte}); }

> // limit나 batchSize를 지정하지 않았으므로 첫번째 batch는 1MB 에서 멈춘다.
> // 결국 1개씩 반복적으로 데이터를 가져오게됨
> var cursor = db.bar.find()

> cursor.objsLeftInBatch()
1

 

반응형

+ Recent posts