MongoDBの集計フィルター($filter)で2つのフィールドを比較する方法
MongoDBの集計パイプライン内で、配列の要素をドキュメントの別フィールドと比較して絞り込みたいケースはよくあります。このような場合には、aggregate()メソッドと$filter演算子を組み合わせることで実現できます。本記事では、具体的なサンプルコードを使いながら、その手順をわかりやすく解説します。
1. サンプルコレクションの作成
まず、insertOne()メソッドを使って、ドキュメントを含むコレクションを作成します。
> db.demo137.insertOne(
... {
... Name1:"Chris",
... Name2:"David",
... Detail1:[
... {_id:"John", Name3:"Chris"},
... {_id:"Chris", Name3:"Chris"},
... ],
... Detail2:[{_id:"David", Name3:"Chris"},
... {_id:"Carol", Name3:"Chris"},
... {_id:"John", Name3:"Chris"}]
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e31b4cefdf09dd6d08539a0")
}このドキュメントには、Name1とName2という2つの文字列フィールドに加え、それぞれに対応するDetail1とDetail2という配列フィールドが含まれています。
2. find()メソッドでドキュメントを確認
find()メソッドを使って、コレクション内のすべてのドキュメントを表示してみましょう。
> db.demo137.find();
実行すると、次のような出力が得られます。
{
"_id" : ObjectId("5e31b4cefdf09dd6d08539a0"), "Name1" : "Chris", "Name2" : "David", "Detail1" : [
{ "_id" : "John", "Name3" : "Chris" },
{ "_id" : "Chris", "Name3" : "Chris" } ], "Detail2" : [ { "_id" : "David", "Name3" : "Chris" },
{ "_id" : "Carol", "Name3" : "Chris" }, { "_id" : "John", "Name3" : "Chris" }
]
}3. 集計フィルターで2つのフィールドを比較する
ここが本記事のポイントです。$projectステージの中で$filterを使用し、配列内の各要素の_idと、ドキュメント直下のName1・Name2フィールドをそれぞれ比較します。2つのフィールドを比較するクエリは以下の通りです。
> db.demo137.aggregate([
... {
... $project: {
... _id: 0,
... Name1: 1,
... Name2: 2,
... Detail1: {
... $filter: {
... input: "$Detail1",
... as: "out",
... cond: {
... $eq: ["$$out._id", "$Name1" ]
... }
... }
... },
... Detail2: {
... $filter: {
... input: "$Detail2",
... as: "out",
... cond: {
... $eq: ["$$out._id", "$Name2" ]
... }
... }
... }
... }
... }
... ])4. 実行結果
上記のクエリを実行すると、次のような出力が得られます。
{
"Name1" : "Chris", "Name2" : "David", "Detail1" : [
{ "_id" : "Chris", "Name3" : "Chris" } ], "Detail2" : [ { "_id" : "David", "Name3" : "Chris" }
]
}解説:$filterの仕組み
結果を見ると、Detail1からは_idが「Chris」(Name1と一致)の要素だけが、Detail2からは_idが「David」(Name2と一致)の要素だけが抽出されていることがわかります。
この動作の鍵となっているのが$filterの各パラメータです。
- input: フィルタリングの対象となる配列(ここでは
$Detail1や$Detail2)を指定します。 - as: 配列の各要素を参照するための変数名を定義します。ここでは「out」という名前を付けています。
- cond: 各要素を残すかどうかを判定する条件式です。変数を参照する際は
$$outのようにドル記号を2つ重ねる点に注意してください。
条件式内では、$eq演算子を使って$$out._id(配列要素の_id)と$Name1(ドキュメントのフィールド)を比較しています。このように、$filterのcond内でドキュメントの他のフィールドを参照できるため、集計パイプラインの中で柔軟にフィールド間比較を行うことが可能です。
-
MongoDBの集計パイプラインで点数が最も少ない2つのドキュメントを取得する方法
点数(Marks)の昇順に並べ替えたリストを取得するには $sort を使用します。さらに $limit: 2 を組み合わせることで、点数が最も少ない2件のドキュメントだけを表示できます。ここでは、実際に動作を確認できるよう、サンプル用のコレクションを作成していきましょう。1. サンプルコレクションの作成まずは insertOne() メソッドを使って、4件のドキュメントを登録します。> db.demo709.insertOne({Name:"John","Marks":75}); { "acknowledged
-
MongoDBの集計パイプラインで複数フィールドをカウントする方法($facet活用)
MongoDBで複数のフィールドごとにドキュメントをカウントしたい場合、$facet演算子を使うのが効果的です。$facetは、同じ入力ドキュメント群に対して、単一のステージ内で複数の集計パイプラインを同時に処理できる強力な機能です。この記事では、実際にコレクションを作成し、$facetを組み合わせた集計クエリで複数フィールドの値をカウントする手順を解説します。1. サンプルコレクションの作成まず、insertOne()メソッドを使ってサンプルドキュメントを挿入します。各ドキュメントにはdetails1・details2・details3という3つのネストされたフィールドを持たせます。>