DB/MongoDB

[MongoDB] 쿼리

snail voyager 2023. 3. 15. 00:01
728x90
반응형

4.1 find

  • 첫 매개변수에 가져올 도큐먼트를 결정
  • 쿼리 도큐먼트에 키/값 쌍을 추가해 검색을 제한
  • 여러 개의 키/값 쌍은 '조건1 AND 조건2 AND...'
> db.c.find()	//빈 쿼리 도큐먼트는 컬렉션 전체 조회
> db.c.find({})	//동일
> db.users.find({"username" : "joe"})	//문자열형이 일치하는 도큐먼트 조회
> db.users.find({"username" : "joe", "age" : 27})

4.1.1 반환받을 키 지정

  • 두 번째 매개변수에 반환받을 키를 지정
  • 네트워상의 데이터 전송량과 클라이언트 측에서 디코딩하는 데 시간, 메모리 절약
  • "_id" 키는 지정하지 않아도 항상 반환, 제외도 가능
> db.users.find({}, {"username" : 1, "email" : 1})	//_id, username, email
> db.users.find({}, {"fatal_weakness" : 0})	//fatal_weakness 키 제외

4.1.2 제약 사항

  • 쿼리 도큐먼트 값은 반드시 상수
  • 도큐먼트 내 다른 키의 값을 참조 불가
> db.stock.find({"in_stock" : "this.num_sold"})	//불가

4.2 쿼리 조건

4.2.1 쿼리 조건절

  • <, <=, >, >= 비교 연산자는 $lt, $lte, $gt, $gte
  • $ne 키 값이 일치하지 않는 도큐먼트를 찾는 데 사용, 모든 데이터형에 사용
> db.users.find({"age" : {"$gtd" : 18, "$lte" : 30}})	// 18~30
> start = new Date("01/01/2007")
> db.users.find({"registered" : {"$lt" : start}})	// < start
> db.users.find({"username" : {"$ne" : "joe"}})	// joe가 아닌 사용자

4.2.2 OR 쿼리

  • $in 하나의 키에 일치시킬 값이 여러개, 조건 배열
  • 서로 다른 데이터형 사용 가능
  • $nin 은 $in 과 반대로 일치하지 않는 도큐먼트 반환
> db.raffle.find({"ticket_no" : {"$in" : [752, 542, 390]}})
> db.users.find({"user_id" : {"$in" : [12345, "joe"]}})
> db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}})
  • $or 은 가능한 조건들의 배열을 취한다
  • 다른 조건절도 포함 가능
  • $or 연산자가 항상 작동하는 동안에는 가능한 한 $in 사용. 쿼리 옵티마이저가 $in 을 더 효율적
> db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]})
> db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}},
			{"winner" : true}]})

4.2.3 $not

  • $not 은 메타 조건절, 어떤 조건에도 적용 가능
> db.users.find({"id_num" : {"$mod" : [5,1]}})
> db.users.find({"id_num" : {"$not" : {"$mod" : [5,1]}}})

4.3 형 특정 쿼리

4.3.1 null

  • 키가 null 인 값을 쿼리하면 해당 키를 갖지 않는 도큐먼트도 반환
  • 값이 null 인 키만 찾고 싶으면 $exists 조건절 사용
> db.c.find({"z" : {"$eq" : null, "$exists" : true}})

4.3.2 정규 표현식

  • $regex 는 쿼리에서 패턴 일치 문자열을 위한 정규식 기능 제공
  • 펄 호환 정규 표현식 (Perl Compatible Regular Expression) 라이브러리 사용
  • 정규 표현식 또한 스스로와 일치하는 도큐먼트 쿼리 가능
> db.users.find({"name" : {"$regex" : /joe/i}})	//대소문자 구별 없이
> db.users.find({"name" : /joey?/i})	//joe, joey
> db.foo.insertOne({"bar" : /baz/})
> db.foo.find({"bar" : /baz/})

4.3.3 배열에 쿼리하기

배열 요소 쿼리는 스칼라 쿼리와 같은 방식으로 동작하도록 설계

$all 연산자

  • 2개 이상의 배열 요소가 일치하는 배열을 찾을 때 사용
  • 순서는 무시
  • 배열 내 특정 요소를 쿼리하려면 key.index 구문을 이용해 순서 지정
> db.foo.find({"fruit" : {"$all" : ["appple", "banana"]}})	//순서 무시
> db.foo.find({"fruit" : ["apple", "banana", "peach"]})	//순서, 값 일치
> db.foo.find({"fruit.2" : "peach"})	//세번째 요소와 일치

$size 연산자

  • 특정 크기의 배열을 쿼리하는 조건절
  • 다른 $ 조건절과 결합해 사용 불가
> db.foo.find({"fruit" : {"$size" : 3}})
> db.foo.update(criteria, 
	{"$push" : {"fruit" : "strawberry"}, "$inc" : {"size" : 1}})	//size 키 값을 증가

$slice 연산자

  • find의 두번째 매개변수에는 반환받을 특정 키를 지정
  • $slice 연산자로 배열 요소의 부분집합을 반환
  • offset 과 요소 개수를 지정해 원하는 범위의 결과 반환
  • 특별히 명시하지 않는 한 모든 키를 반환
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : 10}})	//앞에서 10개
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -10}})	//뒤에서 10개
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : [23, 10]})	//24~33

일치하는 배열 요소의 반환

  • $ 연산자를 사용하여 일치하는 요소를 반환
> db.blog.posts.find({"comments.name" : "bob"}, {"comments.$" : 1})	//첫번째로 일치하는 댓글만 반환

배열 및 범위 쿼리의 상호작용

  • {"x" : {"$gt" : 10, "$lt" : 20}} x는 10보다 크고 20보다 작은
    • x 필드가 배열이라면 각 절의 조건을 충족하는 도큐먼트가 일치. 서로 다른 배열 오소와 일치 가능
    • {"x" : [5, 25]} 둘다 10과 20 사이는 아니지만, 25는 첫째 절과 일치, 5는 둘째 절과 일치
  • $elemMatch 연산자 두 절을 하나의 배열 요소와 비교
    • 비배열 요소를 일치시키지 않음
  • 쿼리하는 필드에 인덱스가 있다면 min, max 함수를 사용해 $gt, $lt 값 사이로 인덱스 범위를 제한해 쿼리 가능
  • 배열에 대한 $gt, $lt 쿼리의 인덱스 한계는 비효율적
> db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}})	//결과 없음
> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}}).min({"x" : 10}).max({"x" : 20})

4.3.4 내장 도큐먼트에 쿼리하기

  • 전체 도큐먼트를 대상으로 하는 쿼리는 일반적인 쿼리와 동일
  • 서브 도큐먼트 전체에 쿼리하려면 서브 도큐먼트와 정확히 일치해야함. 순서도 따짐
  • 내장 도큐먼트에 쿼리할 때는 특정 키로 쿼리하는게 좋음 (스키마가 변경되더라도 정상 조회)
> db.people.find({"name" : {"first" : "Joe", "last" : "Schmoe"}})
> db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"})	//dot notation
  • 모든 키를 지정하지 않고 조건을 정확하게 묶으려면 $elemMatch
> db.blog.find({"comments" : {"$elemMatch" : 
	{"author" : "joe", "score" : {"$gte" : 5}}})

4.4 $where 쿼리

  • 정확하게 표현할 수 없는 쿼리를 자바스크립트를 쿼리의 일부분으로 실행
  • 보안상의 이유로 $where 절 사용을 제한해야함
  • 일반 쿼리보다 훨씬 느림
  • 각 도큐먼트는 BSON에서 자바스크립트 객체로 변환하기 때문에 오래 걸림
  • 인덱스 사용 불가
  • $expr를 사용하면 자바스크립트를 실행하지 않아 더 빨리 쿼리 가능

4.5 커서

  • 클라이언트 측의 커서 구현체는 쿼리의 최종 결과를 제어
  • 결과 개수를 제한, 결과 건너뛰기, 여러 키를 조합한 결과 정렬
  • 셸에서 커서 생성은 쿼리한 결과를 지역 변수에 할당
  • 결과를 얻으려면 next 메서드, 다른 결과가 있는지 확인하려면 hasNext
  • cursor 클래스는 자바스크립트의 반복자 인터페이스를 구현하여 forEach 반복문 사용 가능
  • find를 호출할 때 셸이 DB를 즉시 쿼리하지 않으며 결과를 요청하는 쿼리를 보낼 때까지 기다림
  • 쿼리하기 전에 옵션 추가 가능, 순서 상관 없이 이어 쓰기 가능
  • 한번에 처음 100개 또는 4Mbyte 크기의 결과를 가져옴

4.5.1 제한, 건너뛰기, 정렬

  • limit 상한만 설정
  • skip 조건에 맞는 결과가 적으면 아무 결과도 반환하지 않는다
  • sort 1(오름차순), -1(내림차순)
> db.c.find().limit(3)	//결과 중 3개만 반환
> db.c.find().skip(3)	//결과 중 처음 3개를 건너뛴 나머지 반환
> db.c.find().sort({"username" : 1, "age" : -1})

비교순서

데이터형이 섞여 있는 키는 정의된 순서에 따라 정렬

1.최솟값

2.null

3.숫자(int, long, double, decimal)

4.문자열

5.객체/도큐먼트

6.배열

7.이진 데이터

8.객체ID

9.boolean

10.Date

11.Timestamp

12.정규표현식

13.최댓값

4.5.2 많은 수의 건너뛰기 피하기

skip을 사용하지 않고 페이지 나누기

skip은 생략된 결과물을 모두 찾아 폐기하므로 결과가 많으면 느려진다

> var page2 = db.foo.find(criteria).skip(100).limit(100)	//느림
> var lastest = null;
//첫 페이지
> while (page1.hasNext()) {
	lastest = page1.next();
    display(lastest);
}
//다음 페이지
> var page2 = db.foo.find({"date" : {"$lt" : lastest.date}});
> page2.sort({"date" : -1}).limit(100);

랜덤으로 도큐먼트 찾기

도큐먼트를 입력할 때 랜덤 키를 별도로 추가하는 방법 사용

> db.people.insertOne({"name" : "joe", "random" : Math.random()})
> var random = Math.random()
> result = db.people.findOne({"random" : {"$gt" : random}})

4.5.3 종료되지 않는 커서

  • 커서는 조건에 일치하는 결과를 모두 살펴본 후에 스스로 정리
  • 클라이언트 측에서 유효 영역을 벗어나면 드라이버는 DB에 메시지를 보내 커서 종료
  • 10분 동안 활동이 없으면 DB 커서는 자동으로 죽는다
  • 커서를 타임아웃키시지 못하게 하는 immortal 함수 제공
728x90
반응형