Computer >> 컴퓨터 >  >> 프로그래밍 >> MongoDB

MongoDB에서 특정 필드 기준으로 문서 교집합을 집계 매칭하는 방법

MongoDB에서 여러 문서가 특정 필드 값들을 모두 포함하고 있는지, 즉 문서들의 교집합(intersection)을 집합적으로 매칭해야 하는 경우가 있습니다. 이럴 때는 aggregate() 메서드와 $match, $group, $all, $elemMatch 연산자를 조합하면 효과적으로 해결할 수 있습니다.

1. 샘플 컬렉션 생성하기

먼저 예제로 사용할 컬렉션에 문서를 삽입해 보겠습니다.

> db.demo393.insertOne(
...     {
...        Id1: "1",
...        Name: "Chris",
...        Id2: "100"
...    }
... );
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e5e6dd522064be7ab44e804")
}
> db.demo393.insertOne(
...     {
...        Id1: "1",
...        Name: "Chris",
...        Id2: "101"
...    }
... );
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e5e6dd522064be7ab44e805")
}
> db.demo393.insertOne(
...     {
...        Id1: "3",
...        Name: "Chris",
...        Id2: "100"
...    }
... );
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e5e6dd522064be7ab44e806")
}
> db.demo393.insertOne(
...     {
...        Id1: "3",
...        Name: "Mike",
...        Id2: "101"
...    }
... );
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e5e6dd522064be7ab44e807")
}

2. find()로 전체 문서 확인하기

find() 메서드를 사용하여 컬렉션에 저장된 모든 문서를 조회할 수 있습니다.

> db.demo393.find();

위 쿼리는 다음과 같은 결과를 출력합니다.

{ "_id" : ObjectId("5e5e6dd522064be7ab44e804"), "Id1" : "1", "Name" : "Chris", "Id2" : "100" }
{ "_id" : ObjectId("5e5e6dd522064be7ab44e805"), "Id1" : "1", "Name" : "Chris", "Id2" : "101" }
{ "_id" : ObjectId("5e5e6dd522064be7ab44e806"), "Id1" : "3", "Name" : "Chris", "Id2" : "100" }
{ "_id" : ObjectId("5e5e6dd522064be7ab44e807"), "Id1" : "3", "Name" : "Mike", "Id2" : "101" }

3. 집계 파이프라인으로 교집합 매칭하기

다음은 특정 필드(Id1)를 기준으로 그룹화한 뒤, 각 그룹이 원하는 조건(예: Id2가 "100"과 "101")을 모두 만족하는지 검사하여 문서의 교집합을 찾는 쿼리입니다.

> db.demo393.aggregate([
...     { "$match": { "Name": "Chris" } },
...     { "$group": {
...        "_id": "$Id1",
...        "docs": { "$push": "$$ROOT" },
...        "count": { "$sum": 1 }
...    }},
...     { "$match": {
...        "count": { "$gt": 1 },
...        "docs": {
...           "$all": [
...              { "$elemMatch": { "Id2": "100" } },
...              { "$elemMatch": { "Id2": "101" } }
...           ]
...       }
...    }}
... ])

쿼리 동작 원리 살펴보기

이 집계 파이프라인은 다음 단계로 동작합니다.

첫 번째 $match: Name이 "Chris"인 문서만 우선 필터링합니다.
$group: Id1 값을 기준으로 문서를 그룹화하고, $push$$ROOT를 사용해 그룹에 속한 전체 문서를 배열로 수집하며, $sum으로 그룹 내 문서 개수를 계산합니다.
두 번째 $match: 문서 개수가 1보다 큰 그룹만 남기고, $all$elemMatch를 조합하여 해당 그룹의 문서들이 Id2 값 "100"과 "101"을 모두 포함하는지 확인합니다.

위 쿼리는 다음과 같은 결과를 출력합니다.

{ "_id" : "1", "docs" : [ { "_id" : ObjectId("5e5e6dd522064be7ab44e804"), "Id1" : "1", "Name" : "Chris", "Id2" : "100" }, { "_id" : ObjectId("5e5e6dd522064be7ab44e805"), "Id1" : "1", "Name" : "Chris", "Id2" : "101" } ], "count" : 2 }

결과를 보면 Id1이 "1"인 그룹만 반환되었습니다. 이 그룹에는 Id2가 "100"인 문서와 "101"인 문서가 모두 포함되어 있어 교집합 조건을 충족하기 때문입니다. 반면 Id1이 "3"인 Chris의 문서는 Id2가 "100"뿐이라 조건에 맞지 않아 제외되었습니다.