MongoDB에서 배열 안에 중첩된 JSON 객체의 특정 데이터만 추출하고 싶을 때가 있습니다. 이럴 때 findOne() 메서드와 $elemMatch 연산자를 함께 사용하면 원하는 중첩 데이터만 효율적으로 가져올 수 있습니다. 이번 글에서는 실제 예제를 통해 그 과정을 단계별로 살펴보겠습니다.
1. 예제 컬렉션 생성하기
먼저 테스트용 컬렉션에 문서를 삽입합니다. 아래 예제는 학생 정보와 함께 과목(Subjects) 배열, 그리고 각 과목마다 강사 정보(InstructorDetails)가 중첩된 구조입니다.
> db.demo109.insertOne(
... {
... "Name" : "Chris",
... "Subjects" : [
... {
... "Id" : "100",
... "Name":"MySQL",
... "InstructorDetails" : [
... {
... "Name" : "John"
... }
... ]
... },
... {
... "Id" : "101",
... "Name":"MongoDB",
... "InstructorDetails" : [
... {
... "Name" : "Mike"
... }
... ]
... }
... ]
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e2ee7df9fd5fd66da21447a")
}
문서가 정상적으로 삽입되면 위와 같이 acknowledged: true와 생성된 ObjectId가 반환됩니다.
2. 전체 문서 확인하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 확인할 수 있습니다.
> db.demo109.find();
실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e2ee7df9fd5fd66da21447a"), "Name" : "Chris", "Subjects" : [
{ "Id" : "100", "Name" : "MySQL", "InstructorDetails" : [ { "Name" : "John" } ] },
{ "Id" : "101", "Name" : "MongoDB", "InstructorDetails" : [ { "Name" : "Mike" } ] }
]
}
현재 Subjects 배열에는 두 개의 과목(MySQL, MongoDB)이 들어 있는 것을 볼 수 있습니다.
3. $elemMatch로 중첩 JSON 데이터만 조회하기
이제 핵심 단계입니다. findOne()의 첫 번째 인자로 검색 조건(Name: "Chris")을 지정하고, 두 번째 인자인 프로젝션(projection) 부분에 $elemMatch를 사용하면 조건에 일치하는 배열 요소만 반환받을 수 있습니다.
> db.demo109.findOne(
... { Name: "Chris"}
... , { 'Subjects': { $elemMatch:{'Id':"100"} } }
... , function (err, doc) { console.log(doc) });
위 쿼리의 실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e2ee7df9fd5fd66da21447a"),
"Subjects" : [
{
"Id" : "100",
"Name" : "MySQL",
"InstructorDetails" : [
{
"Name" : "John"
}
]
}
]
}
결과 분석 및 정리
출력 결과를 보면 Id가 "100"인 과목(MySQL)과 해당 과목의 강사 정보(John)만 정확하게 반환된 것을 확인할 수 있습니다. Id가 "101"인 MongoDB 과목은 결과에서 제외되었습니다.
정리하면 다음과 같습니다.
- findOne(): 조건에 맞는 첫 번째 문서 하나만 반환합니다. 여러 개가 필요하다면 find()와 함께 사용할 수도 있습니다.
- $elemMatch: 배열 내부 요소에 여러 조건을 적용하고, 일치하는 요소만 선택적으로 반환할 때 사용합니다.
- 프로젝션에 다른 필드를 추가하지 않으면 기본적으로 _id만 함께 반환됩니다. _id도 제외하고 싶다면 프로젝션에
_id: 0을 추가하면 됩니다.
이처럼 findOne()과 $elemMatch를 조합하면 깊게 중첩된 JSON 구조에서도 필요한 데이터만 간결하고 효율적으로 조회할 수 있습니다.