[개발심화] MongoDB CRUD - 7주차 (2)

Hong·2022년 10월 29일
0




mongoDB 비교연산자

$lte

{"필드 값" : {$lte : 70}}

예를들어
필드 값이 70보다 같거나 작은 녀석들을 가져와 줌


$ne

{"필드 값" : {$ne : "Subscriber"}}

필드 값이 Subscriber가 아닌 사람들을 들고옴


Shell에서 실행해보면 다음과 같음



참고로 지난 시간에 적었던
쿼리 연산자는 데이터 베이스내에서 데이터를 찾는 다양한 방법을 제공한다
하지만
비교 연산자는 특정한 범위 내의 데이터를 찾을 수 있게한다.




mongoDB 논리연산자

논리연산자에는 어떤 녀석들이 있는가?

아래는 작성 구조다

nor
만약 result라는 필드 값이 "A", "B"가 들어있지 않은 값들만 얻고 싶다면

{$nor : [{result : "A"}, {result : "B"}]}

적어주면 된다


근데 만약 E, D의 값도 제외한 result필드 값을 가져오고 싶다면

{$nor : [{result : "A"}, {result : "B"}, {result : "E"}, {result : "D"}]}

적어주면 된다



and

and는 조금 특별한 논리연산자다

Companies 컬렉션에서 총 임직원의 수가 25보다 크고 100보다 작은 회사를 알아보기 위해 첫 번째처럼 $and 쿼리를 사용하여 작성할 수도 있다.
하지만 동일한 필드에 대해 쿼리하므로 $and를 제거해 두 번째 쿼리처럼 더 단순하게 작성할 수도 있다.
그런 다음 두 조건을 하나로 결합하면 세 번째 쿼리처럼 더더욱 단순하게도 작성이 가능하다.

이렇게 $and를 명시하지 않고 두 개의 조건을 하나로 결합하여 쿼리를 작성할 수 있다.


그러면 $and를 언제 명시적으로 포함해야 할까?

일반적인 규칙으론 쿼리에 동일한 연산자를 두 번 이상 포함해야 할 때 $and를 명시한다.

예를 들어 Routes 컬렉션에서 ICN을 통과하는 CR2 및 A81 비행기의 수를 확인해야 할 때 ICN을 통과하는 모든 비행기를 얻으려면 출발지, 또는 목적지 공항이 ICN 이어야 한다.
또한 특정 비행기 유형을 얻기 위해 비행기 유형이 CR2 또는 A81이여야 한다는 조건도 필요한다.
두 조건을 모두 충족하는 비행기의 수를 얻기 위해 첫 부분에 $and를 명시적으로 추가한 다음, 두 개의 $or 조건을 배열 안에 포함한다.

이렇게 동일한 연산자를 두 번 이상 포함해야 할 때는 $and를 명시한다.




mongoDB 표현연산자


Trips 컬렉션에서 얼마나 많은 사람들이 자전거를 대여한 곳에 다시 자전거를 반납하는지 알아보려고 한다.

해당 도큐먼트에서 모든 station은 그와 관련된 name 필드와 id 필드가 존한다. 이 중 id 필드를 가지고 쿼리를 작성해 보겠다.

$expr를 사용하면 해당 값이 어떤 필드와 같아야 하는지 지정하지 않고도 자체적으로 동일한 도큐먼트 내에서 start station id 값과 end station id 값을 직접 비교할 수 있다.

이렇게 $expr를 사용하여 같은 곳에서 대여하고 반납한 모든 결과에 대해 가져올 수 있습니다.


근데 왜 쿼리문에 $가 이곳 저곳 붙어있을까?

$는 MQL에서 많은 초능력을 가지고 있다.

그중 하나는 연산자를 사용할 때를 나타내는 것이며,
다른 하나는 필드 이름 자체가 아니라 해당 필드의 값을 향하고 있음을 나타내는 것이다.

해당 도큐먼트에서 이와 같은 표현식을 날릴 때 $start station id는 값인 439를 의미한다.


실제로 어떻게 쓰이는지 더 알아보자


이제 Trips 컬렉션에서 몇 명이 1200초 이상 자전거를 타고 다시 시작 지점에 자전거를 반납했는지 알아본다.
다음과 같이 $expr를 사용하여 쿼리를 작성할 수 있다.

이제 이 쿼리를 분석하여 쿼리가 실제로 수행하는 작업을 자세히 살펴보겠습니다.

먼저 "$and" 안에 $gt와 $eq를 추가했다.
이는 우리가 비교 연산자를 사용하는 방법을 배운 것과는 약간 다르다.

MySQL에서 비교 연산자 구문은 먼저 필드를 작성하고 나중에 적용되는 비교 연산자를 작성한다.
그러나 이 구문은 집계 표현식을 사용한다. 비슷해 보이지만 문법이 약간 다르다. 집계 구문에서는 연산자를 먼저 작성하고 다음으로 필드와 값을 작성한다.




mongoDB 배열연산자

배열 요소의 순서를 신경쓰지 않고 특정 요소를 포함하는 모든 도큐먼트를 찾는 방법을 알아보자

$all
MQL에는 "$all"이라는 훌륭한 연산자가 있다.

이 쿼리는 배열 필드에 지정한 요소가 있는 모든 도큐먼트를 반환한다

$all을 사용하면 배열 요소의 순서와 상관없이 지정된 요소가 포함된 모든 도큐먼트를 찾을 수 있다.


$size

반환된 결과를 살펴보니 amenities가 많이 포함될수록 숙소가 보통 더 비싸진다는 것을 알게 되었다.

이제 배열 연산자를 이용해 배열의 길이로 결과를 제한해 보자.
배열의 길이에 따라 결과 커서를 제한하려면 쿼리에 $size를 추가한다.

$size : 20으로 정확히 20개의 amenities를 가지며 지정한 요소가 모두 배열에 포함된 도큐먼트만 반환된다.

특정한 요소를 찾지 않는다면, $size만을 사용하여 배열 길이로만 쿼리할 수도 있다.




배열연산자와 Projection

내가 원하는 필드의 값만 들고올 수 있게 하는 것이 projection이다

어떤 구조에서 적어주는가?

Shell에서 실행시키면 아래와 같은 결과값을 가져다 줌

문법을 알아보자

$elematch

find 명령에서는 첫 번째 인자인 쿼리에 해당하는 도큐먼트를 찾은 뒤 Projection한다.
$elemMatch는 지정한 배열 필드가 도큐먼트에 존재하고 조건에 맞는 요소가 있는 경우에만 해당 필드를 결과에 포함시킨다.




어떻게 filed값의 도큐먼트 안의 도큐먼트에 접근할 수 있을까?

이러한 방식과 유사하게 배열안의 중첩된 도큐먼드에도 접근할 수 있음

$regex : 문장 속에서 일치하는 문자열을 찾는다

정규식 연산자인 $regex를 이용하여 일치시키려는 문자열을 지정할 수 있다


출력해주면 이렇게 나온다



근데 더 짧고 편하게 적을 수 있는 방법도 존재함

모든 도큐먼트에서 배열의 첫 번째 요소만이 아닌 배열 요소 전체를 검색합니다.

이 사람이 아직 회사에 있는지를 확인할 수 있는 is past라는 필드가 있다.
만약 그 사람이 회사를 떠났다면 그 값은 true이어야 한다.
그리고 배열 요소의 person 필드 아래에 있는 first name 필드 값은 Mark여야 한다.

편리한 elemMatch 연산자를 사용해 모든 배열 요소를 살펴보고 조건과 일치하는지 알 수 있다.
이 경우 find 명령은 이전 두 개의 쿼리보다 훨씬 짧아진다.




Aggregation Framework

Aggregation Framework는 MongoDB에서 데이터를 쿼리하는 가장 간단한 방법 중 하나이다.

MongoDB 쿼리 언어를 사용하는 모든 작업은 Aggregation Framework를 사용해서도 수행할 수 있다.

MongoDB에서 제공하는 Airbnb 데이터베이스를 이용해 $aggregate 문법에 대해 자세히 살펴보겠다.
amenities 중 하나로 Wifi가 포함된 모든 도큐먼트를 찾고 결과에 가격과 주소만 포함하려 한다.


앞에서 다룬 MQL에서는 find 명령을 사용하여 쿼리와 Projection을 한다.
Aggregation Framework에서는 find가 아닌 aggregate 명령을 사용한다.
구문을 살펴보고 서로의 공통점과 차이점을 살펴보겠다.


aggregate를 사용하면 도큐먼트를 필터링하지 않고 그룹으로 데이터를 집계하거나 데이터를 수정할 수 있다.


aggregate를 사용하면 데이터 찾기 및 프로젝션 없이 작업을 수행하거나 계산할 수 있다.


aggregate를 사용할 땐 대괄호를 이용해 배열을 인자로 사용한다.
이는 파이프라인처럼 배열 요소의 순서대로 작업을 하기 때문이다.


그래서 해당 쿼리에선 파이프라인 작업 순서대로 amenities 배열에 Wifi가 포함되는 도큐먼트를 찾기 위해 $match 연산자를 사용하고
그렇게 찾은 도큐먼트들을 $project 연산자를 사용하여 price와 address 필드만 Projection한다.

profile
Notorious

0개의 댓글