MongoDB
→ 배열 연산자


‘쿼리’에 대한 배열 연산자

배열 기본 검색

  • 테스트 데이터 구성
db.inventory.insertMany([
	{ item : "journal", qty : 25, tags : ["blank", "red"]},
	{ item : "notebook", qty : 50, tags : ["red", "blank"]},
	{ item : "paper", qty : 100, tags : },
	{ item : "planer", qty : 75, tags : ["blank", "red"]},
	{ item : "postcard", qty : 45, tags : ["blue"]},
]);


  • 단일 요소 기본 검색
db.inventory.find({tags:"red"}, {_id:false})

// 결과
{"item" : "journal", "qty" : 25, "tags" : ["blank", "red"]}
{"item" : "notebook", "qty" : 50, "tags" : ["red", "blank"]}
{"item" : "paper", "qty" : 100, "tags" : ["red", "blank", "plain"]}
{"item" : "plnner", "qty" : 75, "tags" : ["blank", "red"]}

※ red 문자열이 들어있는 도큐먼트가 모두 검색되었음


$all

  • 별도 옵션이 없으면 입력한 요소를 입력한 순서 그대로 모두 포함하는 도큐먼트 검색
db.inventory.find({tags : ["red", "blank"]}, {_id:false})

// 결과
{"item" : "notebook", "qty" : 50, "tags" : ["red", "blank"]}

순서에 상관없이 입력한 요소를 모두 포함하는 도큐먼트를 검색하고자할 때 $all 오퍼레이터 사용

db.inventory.find({tags : { $all : ["red", "blank"]} }, {_id:false})

// 결과
{"item" : "journal", "qty" : 25, "tags" : ["blank", "red"]}
{"item" : "notebook", "qty" : 50, "tags" : ["red", "blank"]}
{"item" : "paper", "qty" : 100, "tags" : ["red", "blank", "plain"]}
{"item" : "plnner", "qty" : 75, "tags" : ["blank", "red"]}

의미를 생각해보면, $and 연산자로도 동일한 값을 얻을 수 있다.

{ <field> : { $all :[ <value1>, <value2>, ...] }
{ $and : [{<filed1>:<value1>}, {<filed2>:<value2>}, ...] }


$elemMatch

  • 두 가지 조건을 동시에 만족하는 요소가 있는 도큐먼트 검색.
    예시) 5 보다 크고 10 보다 작은 요소가 하나라도 있는 도큐먼트 검색
db.inventory.find({ tags : {$elemMatch : { $gt : 5, $lt : 10 } } })

만약 $elemMatch 연산자를 사용하지 않고

db.inventory.find({ tags : { $gt : 5, $lt : 10 } })로 검색하게되면 5보다 큰 요소거나 10보다 작으면 검색결과에 포함된다(예시: [15,1])

  • elemMatch, all 연산자를 응용한 쿼리
db.example.find({
  stock : {
    $all : [
      { $elemMatch : { size : "M", num : { $ge: 50} } },
      { $elemMatch : { num : 100, color : "green" } },
    ]
  }
})


$size

배열이 해당크기와 같은 도큐먼트 검색

db.inventory.find({ "tags" : { $size : 3 } }, { _id : false })

// 결과
{ "item" : "paper", "qty" : 100, "tags" : ["red", "blank", "plain"] }


‘프로젝션’에 대한 배열 연산자

$slice

: 특정 인덱스(위치)에 해당되는 값만 추출 후 노출

앞서 오브젝트값을 갖는 필드에서 특정 필드(프로퍼티)만 노출시키고자 할때 ‘점 연산자’를 사용했었다.

db.people.find({}, {"name.first": true})
// 결과
{name: {first:"철수"}}
{name: {first:"영희"}}
{name: {first:"수영"}}
{name: {first:"희영"}}

그럼 배열을 갖는 필드에서 특정 순번(0)의 요소만 출력하고자 할때는?

db.inventory.find({}, {"tags.0":true}) // X
db.inventory.find({}, {"tags":{$slice:0}}) // O

db.inventory.find({}, {"tags.0":true}) 이 되지 못하는 이유는 0번째 인덱스를 찾는게 아니라 tags라는 오브젝트의 “0”이라는 필드를 갖는 값을 찾기 때문. 즉, tags : {“0” : “TEST”, “1” : “TEST1”} 이러한 형태에서 “0”이라는 필드를 검색

또 한가지 주의해야할 사항으로는 위의 경우, {"tags":{$slice:0}}를 통해 0번째 인덱스’만’ 출력하고자 하는 의도와 달리 다른 필드들까지 모두 출력되는 것을 볼 수 있다.

/* 예시 */
db.inventory.find({}, {"tags":{$slice:1}})
// 결과
{"_id" : ObjectId("~~"), "item" : "journal", "qty" : 25, "tags" : ["blank"]}
{"_id" : ObjectId("~~"), "item" : "notebook", "qty" : 50, "tags" : ["red"]}
{"_id" : ObjectId("~~"), "item" : "paper", "qty" : 100, "tags" : ["red"]}
{"_id" : ObjectId("~~"), "item" : "planner", "qty" : 75, "tags" : ["blank"]}
{"_id" : ObjectId("~~"), "item" : "postcard", "qty" : 45, "tags" : ["blue"]}

그 이유는 $slice 연산자를 사용하게 될 경우 앞서 프로젝션 설정에서 배운 true도 false도 아닌, boolean값과는 무관한 설정이기 때문에, 기존 프로젝션의 default 설정대로 나머지 필드까지 모두 출력되는 것과 같다.(이건 내생각)

tags 필드의 특정 인덱스만 출력 하고싶으면 이 외의 필드에 대한 프로젝션 설정까지 필요하다

/* 예시 */
db.inventory.find({}, {"tags":{$slice:1}, _id:false, item:false, qty:false})
// 결과
{"tags" : ["blank"]}
{"tags" : ["red"]}
{"tags" : ["red"]}
{"tags" : ["blank"]}
{"tags" : ["blue"]}

맨 마지막부터 두 개 요소 출력은 -2 db.inventory.find({}, {"tags":{$slice:-2}})

중간 일부 범위 (인덱스 1부터 3까지(총3개)) 출력은 배열 [1,3]

db.inventory.find({}, {"tags":{$slice:[1,3]}})

$elemMatch

: 특정 조건을 만족하는 요소만 추출 후 노출

db.inventory.find({}, { 
  tags: {$elemMatch: {$regex: /^b/}}, _id:false, item:false, qty:false
})
//결과
{"tags" : ["blank"]}
{"tags" : ["blank"]}
{"tags" : ["blank"]}
{"tags" : ["blue"]}

$

: ‘쿼리’ 조건에 일치했던 값만 출력

/* 사용하지 않은 예 */
db.inventory.find({tag:"red"}, {_id:false, item: false, qty:false})
//결과
{"tag":["blank", "red"]}
{"tag":["red", "blank"]}
{"tag":["red", "blank, plain"]}
{"tag":["blank", "red"]}

/* 사용한 예 */
db.inventory.find({tag:"red"}, {"tags.$":true, _id:false})
//결과
{"tag":["red"]}
{"tag":["red"]}
{"tag":["red"]}
{"tag":["red"]}

Leave a comment