🧩

【MongoDB】groupを用いた集計で中央値を取得したい

2024/05/10に公開

概要

MongoDBではMongoDBの集計($group, $match, $sum, $avgなど)の記事にある通り、キーを指定して合計や平均などを集計することができます。
MongoDB 7.0からmedian (aggregation)という中央値を取得できる機能が追加されたようなので、今回試してみました。

前提

  • 使用したMongoDBのバージョンは7.0です。

実装サンプル

今回はRustでクエリを実装してみました。memo_listという配列項目の配下のevaluationの値を集計します。
MongoDB group by array inner-elementsの記事を参考に、一度配列をunwindした後に集計しています。

pub async fn get_sample_post_evaluation_aggregate(
    db: Database,
    account_user_id: String,
) -> Result<Vec<db_model::SamplePostAggregate>, Error> {
    let collection = db.collection::<db_model::SamplePost>(db_model::SAMPLE_POST_COLLECTION);
    // 集計して中央値を取得するクエリ
    let mut pipeline = vec![
        doc! { "$match": doc! { "account_user_id": account_user_id.clone() } },
        doc! { "$unwind": "$memo_list" },
        doc! { "$group": doc! {
            "_id": doc! { "name": "$memo_list.name" },
			"median": doc! { "$median": doc! {  "input":"$memo_list.evaluation", "method": "approximate" } },
        } },
    ];
    // 取得した結果を集計用のmodelにparse
    let mut results: Vec<db_model::SamplePostAggregate> = Vec::new();
    let aggregate_result = collection.aggregate(pipeline, None).await;
    match aggregate_result {
        Ok(cur) => {
            let mut cur_mut = cur;
            while let Some(result) = cur_mut.try_next().await? {
                if let Ok(post_aggregate) =
                    bson::from_document::<db_model::SamplePostAggregate>(result)
                {
                    results.push(post_aggregate)
                }
            }
        }
        Err(error) => return Err(error),
    }

    return Ok(results);
}

Discussion