[CS] MongoDB CRUD(심화) 배열 연산자 / 배열과 Sub Document Day-55

cptkuk91·2022년 2월 2일
0

CS

목록 보기
92/139

배열 연산자

  • $elemMatch(projection)
  • $elemMatch(query)

Document에 너무 많은 필드와 정보가 있을 때 정보를 확인하기 어려울 때가 있습니다.

이를 완화하기 위해 find 쿼리에 프로젝션을 추가해 현재 관심있는 필드만 결과로 가져올 수 있습니다.

$elemMatch(projection) - 원하는 필드만 가져오자!

데이터베이스에서 조건에 해당하는 Document를 찾고 특정 필드만 결과에 포함하는 쿼리입니다.

ex) address와 price필드만 결과로 가져올 수 있도록

ds.컬렉션이름.find({"amenities": {"$size":20, "$all": ["Internet", "Wifi", "Heating",...]}}, {"price": 1, "address": 1}).pretty()

// 두 번째 인자를 통해서 price와 address만 가져올 수 있습니다.

find쿼리의 첫 번째 인자에서 찾으려는 Document 조건이 옵니다. 두 번째 인자로 우리가 찾고 있는 필드를 구체적으로 설명하는 projection입니다.


projection 문법에서의 0과 1

프로젝션을 사용할 때, 0 과 1을 사용해 결과에서 표시하거나 표시하지 않을 필드를 지정할 수 있습니다.

1을 사용하는 경우 지정한 필드와 _id 필드만 가져옵니다.
0을 사용하는 경우 지정한 필드를 제외한 모든 필드가 표시됩니다.

주의사항: 한 번의 프로젝션에서 0과 1을 혼합할 수 없습니다.

db.컬렉션이름.find({query}, {projection})

ex) 85점 이상의 성적을 받고, 431 수업을 듣는 학생을 찾아보자.

db.grades.findOne()

// 아래는 출력 결과
{
	...
    ...
    "scores":[
    	{
        	"type": "exam",
            "score": "21"
        },
        {
        	"type": "quiz",
            "score": "58"
        },
        {
        	"type": "homework",
            "score": "83"
        },
        {
        	"type": "homework",
            "score": "90"
        },
    ],
    "class_id": 265
}

우선 grades Collection의 Document를 찾아보자.
scores 필드는 배열임을 알 수 있습니다.

type필드보다 score 필드에 관심을 가져야한다.

scores 내 score 필드에 접근하기 위해서는 elemMatch를 사용하면됩니다.

elemMatch

db.grades.find({"class_id":431}, "scores":{"$elemMatch":{"score":{"$gt":85}}});

풀어서 해석하자면 grades collection에서 class_id 431을 찾고, $elemMatch를 통해서 지정한 배열 필드가 Document에 존재하고 조건에 맞는 요소가 있는 경우 해당 필드를 결과에 포함시킵니다.

score는 scores 배열 필드 안에 존재하기 때문에 $elemMatch를 통해서 원하는 결과를 출력받을 수 있습니다.

elemMatch 예제2

db.grades.find({"scores":{"$elemMatch":{"type":"extra credit"}}}).pretty();

위 명령어는 grades Collection에서 scores 필드 내 타입이 "extra credit"인 학생을 찾는 명령어 입니다.

scores 배열 내 type 필드를 가지고 type이 "extra credit"인 학생을 찾는 것입니다.


정리

projection

db.collection.find({query}, {projection});

projection에서 0과 1을 사용하여 특정 필드를 포함 또는 제외할 수 있습니다.
0과 1은 혼용해서 사용할 수 없습니다.

$elemMatch

{field:{"$elemMatch":{filed:value}}}

첫 번째 인자에서 쓰일 경우, 배열 필드의 서브 Document 필드가 쿼리와 일치하는 문서를 찾습니다.
두 번째 인자에서 쓰일 경우, 지정된 기준과 일치하는 요소가 하나 이상있는 배열 요소만 프로젝션 합니다.


배열과 서브 Document 쿼리하기

MongoDB에서는 유연한 데이터 모델링을 통해 개발자가 데이터를 저장할 방법을 결정할 수 있습니다.

일반적으로 서브 Document 또는 배열로 저장합니다.

ex) 예시

db.trips.findOne();

// 아래는 trips Collection에 대한 결과물

{
	...
    ...
    ...
    ...
    ...
    "start station location":{
    	"type":"Point",
        "coordinate": [
        	-73,
            40
        ]
    },
    "end station location":{
    	"type":"Point",
        "coordinate":[
        	-73,
            40
        ]
    }
}

trips Collection 내에는 start station location, end station location 등 다양한 필드가 존재하고 start station location, end station location 안쪽에는 Sub Document가 있습니다.

Sub Document 쿼리하기

db.trips.findOne({"start station location.type": "Point"});

Dot Notation을 사용해 start station location.type:"Point" 에 접근할 수 있습니다.

db.collection 을 보면 데이터베이스 역시 collection으로 이동 시 Dot Notation을 사용하는 걸 알 수 있습니다.

따라서 Document가 있는 필드로 이동할 때도 점 표기법(Dot Notation)을 사용해 필드의 값을 가져올 수 있습니다.

ex) Sub Document 예제

db.companies.find({"relationship.person.last_name": "Lee"}, {"name": 1}).pretty();

companies Collection 내에서 relationship 접근 relationship 내 person.last_name 필드로 진입한다. 이때 "Lee"라는 사람을 결과로 뽑아낼 수 있다.

ex) relationship 배열에서 first_name이 Mark, title이 CEO를 찾는다면?

db.companies.find({"relationship.person.first_name": "Mark", {"relationship.title": {"$regex": "CEO"}}, {"name": 1}).pretty();

$regex를 통해서 일치한 문자열을 지정할 수 있습니다.


ex) relationship 배열에서 회사를 떠난 사람 중 이름이 Mark인 사람을 찾는다면?

{"is_past": true},
{"person.first_name": "Mark"]

두 개의 조건을 만족해야 합니다.

db.companies.find({"relationship": {"$elemMatch": {"is_past": true, "person.first_name": "Mark"}}}, {"name": 1}).pretty();

$elemMatch를 통해 모든 배열 요소를 살펴보고 조건과 일치하는지 알 수 있습니다.


정리

  • MQL에서 Dot notation을 사용하여 Sub Document 요소를 참조할 수 있습니다.

  • 배열에서 Dot notation을 사용하려면 요소의 위치를 지정해야 합니다.

  • 기본 문법(Syntax)

db.collection.find({"field1.other.anotherField": "value"});

profile
메일은 매일 확인하고 있습니다. 궁금하신 부분이나 틀린 부분에 대한 지적사항이 있으시다면 언제든 편하게 연락 부탁드려요 :)

0개의 댓글