MongoDB Aggregation Pipeline

beluga000·2024년 7월 31일
post-thumbnail

Aggregation Pipeline

MongoDB의 Aggregation Pipeline데이터의 변환 및 집계를 수행할 수 있는 매우 강력한 기능입니다. 여러 단계로 구성된 파이프라인을 통해 데이터베이스 내의 문서를 처리할 수 있습니다. 각 단계는 특정 작업을 수행하며, 단계별로 연산자를 사용하여 원하는 작업을 정의할 수 있습니다.

Aggregation Pipeline 연산자

  1. $match

지정된 조건과 일치하는 문서만 전달하는 연산자, Pipeline의 앞 부분에 배치하여야 처리량을 최적화할 수 있습니다.

{ $match: { status: "A" } }
  1. $group

지정된 필드로 그룹화하고, 집계 함수를 사용하여 각 그룹의 데이터를 집계합니다.

{ $group: { _id: "$status", total: { $sum: "$amount" } } }
  1. $project

문서의 필드를 포함하거나 제외하고, 새로운 필드를 생성할 수 있습니다.

{ $project: { title: 1, author: 1, year: { $year: "$date" } } }
  1. $sort

정렬 조건에 따라 문서를 정렬합니다.

{ $sort: { age: -1 } }
  1. $limit

지정된 개수만큼의 문서를 반환합니다.

{ $limit: 5 }
  1. $skip

지정된 개수만큼의 문서를 건너뜁니다.

{ $skip: 10 }
  1. $unwind

배열 필드를 분해하여 여러 문서로 확장합니다.

{ $unwind: "$items" }
  1. $lookup

다른 컬렉션과 조인하여 데이터를 결합합니다.

{
  $lookup: {
    from: "orders",
    localField: "customerId",
    foreignField: "customerId",
    as: "orders"
  }
}
  1. $addFields

새로운 필드를 추가합니다.

{ $addFields: { totalCost: { $multiply: ["$price", "$quantity"] } } }
  1. $replaceRoot

문서의 루트 요소를 바꿉니다.

{ $replaceRoot: { newRoot: "$items" } }
  1. $out

파이프라인의 출력을 새로운 컬렉션에 저장합니다.

{ $out: "newCollection" }
  1. $count

문서의 수를 세고, 그 결과를 새로운 필드로 반환합니다.

{ $count: "totalCount" }
  1. $facet

여러 개의 하위 파이프라인을 동시에 실행하여, 복잡한 다중 단계 집계 작업을 수행할 수 있습니다.

{
  $facet: {
    "categorizedByPrice": [
      { $match: { price: { $exists: 1 } } },
      { $bucket: { groupBy: "$price", boundaries: [0, 50, 100, 200, 300] } }
    ],
    "categorizedByYear": [
      { $match: { year: { $exists: 1 } } },
      { $bucketAuto: { groupBy: "$year", buckets: 4 } }
    ]
  }
}
  1. $merge

결과를 기존 컬렉션에 병합하거나 새 컬렉션에 저장합니다.

{
  $merge: {
    into: "mergedCollection",
    whenMatched: "merge",
    whenNotMatched: "insert"
  }
}

위 14개의 연산자 외에도 다른 많은 연산자가 존재하기에 각 상황에 맞는 연산자들 사용한다면 더욱 복잡한 쿼리를 작성할 수 있습니다.

Aggregation Pipeline 연산자 예시

sales 컬렉션

[
  { "date": "2023-07-01", "store": "A", "item": "apple", "quantity": 10, "price": 2 },
  { "date": "2023-07-01", "store": "A", "item": "banana", "quantity": 5, "price": 1 },
  { "date": "2023-07-01", "store": "B", "item": "apple", "quantity": 8, "price": 2 },
  { "date": "2023-07-02", "store": "A", "item": "apple", "quantity": 6, "price": 2 },
  { "date": "2023-07-02", "store": "B", "item": "banana", "quantity": 7, "price": 1 }
]
  1. $match를 활용하여 2023-07-01 날짜의 판매만 필터링
{ $match: { date: "2023-07-01" } }
  1. $group을 활용하여 각 상점(store)별로 판매된 총 수량(quantity)과 총 금액(price)을 집계
{ $group: { _id: "$store", totalQuantity: { $sum: "$quantity" }, totalRevenue: { $sum: { $multiply: ["$quantity", "$price"] } } } }
  1. $project를 활용하여 상점(store)별 총 수량(totalQuantity)과 총 금액(totalRevenue)만 표시
{ $project: { store: "$_id", totalQuantity: 1, totalRevenue: 1, _id: 0 } }
  1. $sort를 활용하여 총 수익(totalRevenue) 기준으로 내림차순 정렬
{ $sort: { totalRevenue: -1 } }
  1. $lookup을 활용하여 stores 컬렉션과 조인하여 판매 데이터에 상점의 세부 정보를 결합
{
  $lookup: {
    from: "stores",
    localField: "store",
    foreignField: "storeId",
    as: "storeDetails"
  }
}

예를 들어, 2023-07-01 날짜의 판매 데이터를 필터링하고, 각 상점별로 총 수익을 계산하여 상위 1개의 결과를 얻는 전체 파이프라인은 다음과 같이 작성합니다.

[
  { $match: { date: "2023-07-01" } },
  { $group: { _id: "$store", totalQuantity: { $sum: "$quantity" }, totalRevenue: { $sum: { $multiply: ["$quantity", "$price"] } } } },
  { $project: { store: "$_id", totalQuantity: 1, totalRevenue: 1, _id: 0 } },
  { $sort: { totalRevenue: -1 } },
  { $limit: 1 }
]
profile
Developer

0개의 댓글