MongoDB에서 배열 필드 안에 포함된 하위 문서(subdocument) 중 특정 조건을 만족하는 요소만 추출하고 싶은 경우가 자주 있습니다. 이 글에서는 aggregate 파이프라인의 $match와 $filter 연산자를 활용하여 조건에 맞는 하위 문서만 찾아 반환하는 방법을 예제와 함께 살펴보겠습니다.
1. 샘플 컬렉션 생성하기
먼저 테스트용으로 문서가 포함된 컬렉션을 생성합니다.
> db.demo345.insertOne({
... "UserName" : "Robert",
... "UserDetails" : [
... {
... "isMarried" : false,
... "CountryName":"US"
... },
... {
... "isMarried" : true,
... "CountryName":"UK"
... },
... {
... "isMarried" : false,
... "CountryName":"AUS"
... }
... ]
... })
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5404fdf8647eb59e5620ac")
}
2. 전체 문서 조회하기
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다.
> db.demo345.find();
실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e5404fdf8647eb59e5620ac"), "UserName" : "Robert", "UserDetails" : [
{ "isMarried" : false, "CountryName" : "US" },
{ "isMarried" : true, "CountryName" : "UK" },
{ "isMarried" : false, "CountryName" : "AUS" }
]
}
3. 조건에 맞는 하위 문서만 반환하는 쿼리
다음은 $match로 특정 문서를 먼저 선택한 뒤, $filter를 사용해 UserDetails 배열 중 isMarried가 true인 하위 문서만 남겨서 반환하는 쿼리입니다.
> db.demo345.aggregate([
... {
... $match: { UserName: "Robert" }
... },
... {
... $addFields: {
... UserDetails: {
... $filter: {
... input: "$UserDetails",
... cond: {
... $eq: [ "$$this.isMarried", true ]
... }
... }
... }
... }
... }
... ])
실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e5404fdf8647eb59e5620ac"), "UserName" : "Robert", "UserDetails" : [
{ "isMarried" : true, "CountryName" : "UK" }
]
}
쿼리 동작 원리
- $match: UserName이 "Robert"인 문서만 파이프라인으로 전달합니다.
- $addFields: 기존의 UserDetails 필드 값을 새로운 값으로 교체합니다.
- $filter: 배열을 순회하면서 cond에 정의된 조건(
isMarried가 true)을 만족하는 요소만 남깁니다. 여기서$$this는 현재 순회 중인 배열 요소를 가리키는 변수입니다.
이처럼 $match와 $filter를 조합하면 배열 내부의 하위 문서를 원하는 기준으로 손쉽게 검색하고 반환할 수 있습니다.