MongoDBで異なるコレクション要素の一意のプロパティを合計して結果の価格を取得する方法
MongoDBで複数のコレクション要素(ドキュメント)にまたがる一意のプロパティの値を合計し、最終的な価格(Price)を取得したいケースは少なくありません。こうした処理を実現するには、集計パイプライン(Aggregation Pipeline)の $cond 演算子と $group ステージを組み合わせます。
この記事では、実際のサンプルコードを交えながら、手順を段階的に解説していきます。
サンプルコレクションの作成
まず、insertOne() メソッドを使ってドキュメントを挿入し、コレクション「demo580」を作成します。
> db.demo580.insertOne(
... {
... "Name": "John",
... "Id1": "110",
... "Id2": "111",
... "Price": 10.5
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e918cebfd2d90c177b5bcae")
}
>
> db.demo580.insertOne(
... {
... "Name": "John",
... "Id1": "111",
... "Id2": "",
... "Price": 9.5
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e918cecfd2d90c177b5bcaf")
}
ここでは、同じユーザー「John」に関する2件のドキュメントを用意しました。1件目は Id1 と Id2 の両方に値が入っていますが、2件目は Id2 が空文字列になっている点が特徴です。
登録済みドキュメントの確認
find() メソッドを呼び出すことで、コレクション内のすべてのドキュメントを確認できます。
> db.demo580.find();
実行すると、次のような出力が得られます。
{ "_id" : ObjectId("5e918cebfd2d90c177b5bcae"), "Name" : "John", "Id1" : "110", "Id2" : "111", "Price" : 10.5 }
{ "_id" : ObjectId("5e918cecfd2d90c177b5bcaf"), "Name" : "John", "Id1" : "111", "Id2" : "", "Price" : 9.5 }
一意のプロパティを合計する集計クエリ
それでは、異なるコレクション要素の一意のプロパティを合計するためのクエリを見ていきましょう。
> db.demo580.aggregate([
... {
... $project: {
... Id1: 1,
... Id2: 1,
... Price: 1,
... match: {
... $cond: [
... {$eq: ["$Id2", ""]},
... "$Id1",
... "$Id2"
... ]
... }
... }
... },
... {
... $group: {
... _id: '$match',
... Price: {$sum: '$Price'},
... resultId: {
... $addToSet: {
... $cond: [
... {$eq: ['$match', '$Id1']},
... null,
... '$Id1'
... ]
... }
... }
... }
... },
... {$unwind: '$resultId'},
... {$match: {
... resultId: {
... $ne: null
... }
... }
... },
... {
... $project: {
... Id1: '$resultId',
... Price: 1,
... _id: 0
... }
... }
... ])
このクエリを実行すると、次の出力が得られます。
{ "Price" : 20, "Id1" : "110" }
クエリの仕組み
各ステージの役割は以下の通りです。
- $project ステージ:
$condを使って条件分岐を行い、Id2が空文字列の場合はId1を、そうでなければId2をグループ化キーとなる「match」フィールドとして生成します。 - $group ステージ: 「match」の値ごとにドキュメントをグループ化し、
$sumで価格を合計します。同時に$addToSetによって重複しないIDだけを収集します。 - $unwind / $match ステージ: 配列化された resultId を個別のドキュメントへ展開し、null の要素を除外します。
- 最後の $project ステージ: 出力形式を整え、必要なフィールドのみを返します。
今回の例では、2つのドキュメントが共通のID(110・111)を持っているため、同一のグループとして扱われ、価格 10.5 + 9.5 = 20 という合計値が算出されます。このように $cond と $group を組み合わせることで、重複するIDをまとめながら一意のプロパティごとの合計金額を効率的に取得できます。
-
MongoDBコレクションの全キー(フィールド名)を取得する方法まとめ
この記事は2019年1月18日にObjectRocket.com/blogで公開された内容をもとにしています。 MongoDB®のコレクションに含まれるすべてのキーを把握することは、スキーマの検証、フィールド名のタイプミスのデバッグ、設定すべきでないフィールドの発見など、さまざまな場面で役立ちます。本記事では、MongoDBコレクション内の全キー名を取得する複数の方法を、状況別にわかりやすく解説します。 まず検討したい:ODMやマネージドサービスの活用 ObjectRocketをはじめとする多くのMongoDB-as-a-Service事業者は、ユーザーインターフェース(UI)上で簡単にキーを
-
MongoDBコレクション内の全キー名を取得する方法|MapReduce・Aggregation・シェルなど状況別に解説
スキーマの検証、フィールド名のタイプミスのデバッグ、設定されるべきではないフィールドの発見などを行うには、まずMongoDBコレクション内にどのようなキーが存在するのかを把握しておく必要があります。多くのMongoDB-as-a-Service事業者は、UI上で手軽にこれを実現できる機能を提供しています(ObjectRocketもそのひとつです)。また、経験豊富なMongoDBユーザーの多くは、JavaScript向けのMongooseやPython向けのMongoengineといったオブジェクトドキュメントマッパー(ODM)を導入しています。ODMを使えば、アプリケーション向けの一貫性のある