MongoDB에서 하위 문서(서브도큐먼트)를 쿼리하는 과정에서 배열을 필터처럼 활용하고 싶다면 $setIsSubset 연산자를 사용하면 됩니다. 이 연산자는 첫 번째 배열이 두 번째 배열의 부분 집합인지 판별하여 true 또는 false를 반환하므로, 특정 값 목록에 포함된 요소만 골라내는 필터링 작업에 적합합니다.
1. 샘플 컬렉션 생성
먼저 demo407 컬렉션을 만들고 문서를 하나 삽입해 보겠습니다.
> db.demo407.insertOne(
... {
... Name:"Chris",
... "details" : [
... {
... id:100
... },
... {
... id:110
... },
... {
... id:130
... }
... ]
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e70dffe15dc524f70227677")
}2. 저장된 문서 확인
find() 메서드를 사용하면 컬렉션에 있는 모든 문서를 조회할 수 있습니다.
> db.demo407.find().pretty();
실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : ObjectId("5e70dffe15dc524f70227677"),
"Name" : "Chris",
"details" : [
{
"id" : 100
},
{
"id" : 110
},
{
"id" : 130
}
]
}3. 배열을 필터로 사용하는 쿼리 작성
이제 집계 파이프라인(aggregation pipeline)에서 $match와 $project 단계를 조합하고, $filter 내부에 $setIsSubset을 적용하여 details 배열 중 id가 100 또는 130인 하위 문서만 남기는 쿼리를 작성해 보겠습니다.
> db.demo407.aggregate([
... {$match: { }},
... {$project: {
... "details": {
... $filter: {
... input: "$details",
... as: "output",
... cond: { $setIsSubset: [["$$output.id"],[100, 130]] }
... }
... }
... }}])쿼리 동작 원리
- $match: { } — 조건 없이 모든 문서를 다음 단계로 전달합니다.
- $project — _id와 details 필드만 결과에 포함되도록 지정합니다.
- $filter — input으로 받은 $details 배열의 각 요소를 output 변수에 담아 순회하며 cond 조건을 평가합니다.
- $setIsSubset — 각 하위 문서의 id 값으로 만든 배열(["$$output.id"])이 기준 배열([100, 130])의 부분 집합인지 검사합니다. 따라서 id가 100 또는 130일 때만 true가 되어 해당 요소가 최종 결과에 유지됩니다.
위 쿼리를 실행하면 다음과 같은 결과를 얻을 수 있습니다.
{ "_id" : ObjectId("5e70dffe15dc524f70227677"), "details" : [ { "id" : 100 }, { "id" : 130 } ] }결과를 살펴보면 details 배열에서 id가 110인 요소는 제외되고, 조건에 부합하는 100과 130의 하위 문서만 필터링되어 반환된 것을 확인할 수 있습니다. 이처럼 $setIsSubset과 $filter를 조합하면 복잡한 하위 문서 배열도 손쉽게 원하는 형태로 걸러낼 수 있습니다.