MongoDB에서 $addFields 애그리게이션 단계와 $filter 연산자를 함께 사용하면 배열 필드의 요소들을 조건에 따라 걸러낸 새로운 필드를 만들 수 있습니다. 이 글에서는 실제 예제를 통해 두 기능을 조합하여 사용하는 방법을 단계별로 살펴보겠습니다.
1. 컬렉션 생성 및 문서 삽입하기
먼저 예제로 사용할 컬렉션을 생성하고 문서를 삽입합니다. 아래 명령어는 학생 정보와 과목 목록, 그리고 세부 정보(Details) 배열을 포함한 문서를 저장합니다.
> db.demo118.insertOne(
... {
... "Id" : "101",
... "Name" : "Chris",
... "Subjects" : [
... "MySQL",
... "MongoDB",
... "Java"
... ],
... "Details" : [
... {
... "Name" : "David",
... S:"MongoDB"
... },
... {
... "Name" : "Bob",
... S:"Python"
... }
... ]
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e2f0c0cd8f64a552dae6364")
}2. find() 메서드로 전체 문서 확인하기
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 조회할 수 있습니다.
> db.demo118.find();
위 쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{ "_id" : ObjectId("5e2f0c0cd8f64a552dae6364"), "Id" : "101", "Name" : "Chris", "Subjects" : [ "MySQL", "MongoDB", "Java" ], "Details" : [ { "Name" : "David", "S" : "MongoDB" }, { "Name" : "Bob", "S" : "Python" } ] }3. $addFields와 $filter를 활용한 쿼리 작성하기
이제 핵심인 $addFields 파이프라인 쿼리를 살펴보겠습니다. 이 쿼리는 Details 배열에서 각 요소의 S 값이 Subjects 배열에 포함되어 있는지 확인하고, 조건을 만족하는 요소만 남겨서 Details 필드를 새롭게 정의합니다.
- $addFields: 기존 필드를 덮어쓰거나 새로운 필드를 추가하는 애그리게이션 단계입니다.
- $filter: input으로 지정한 배열을 순회하면서 cond 조건을 통과하는 요소만 반환합니다.
- $in: 특정 값($$out.S)이 대상 배열($Subjects) 안에 존재하는지 검사합니다.
> db.demo118.aggregate([
... {
... "$addFields": {
... "Details": {
... "$filter": {
... "input": "$Details",
... "as": "out",
... "cond": { "$in": ["$$out.S", "$Subjects"] }
... }
... }
... }
... }
... ]).pretty();4. 실행 결과 확인하기
쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : ObjectId("5e2f0c0cd8f64a552dae6364"),
"Id" : "101",
"Name" : "Chris",
"Subjects" : [
"MySQL",
"MongoDB",
"Java"
],
"Details" : [
{
"Name" : "David",
"S" : "MongoDB"
}
]
}결과 분석
원본 데이터의 Details 배열에는 David(MongoDB)와 Bob(Python) 두 개의 요소가 있었습니다. 그러나 Subjects 배열에는 MySQL, MongoDB, Java만 포함되어 있고 Python은 없기 때문에, $in 조건을 통과하지 못한 Bob의 정보는 결과에서 제외되었습니다. 이처럼 $addFields와 $filter를 조합하면 원본 문서를 수정하지 않고도 읽기 작업 시점에 배열 데이터를 유연하게 가공할 수 있습니다.