MongoDBのmapReduce()関数で1つおきのドキュメントを抽出して表示する方法
MongoDBではmapReduce()関数を活用することで、コレクション内のドキュメントを柔軟に加工・フィルタリングできます。この記事では、mapReduce()を使って「1つおき(隔番)」のドキュメントだけを出力する方法を、実際のサンプルコードとともにわかりやすく解説します。
サンプルコレクションの作成
まず、テスト用のコレクションを作成し、insert()メソッドで複数のドキュメントを挿入します。
> db.demo636.insert({id:1});
WriteResult({ "nInserted" : 1 })
> db.demo636.insert({id:2});
WriteResult({ "nInserted" : 1 })
> db.demo636.insert({id:3});
WriteResult({ "nInserted" : 1 })
> db.demo636.insert({id:4});
WriteResult({ "nInserted" : 1 })
> db.demo636.insert({id:5});
WriteResult({ "nInserted" : 1 })
> db.demo636.insert({id:6});
WriteResult({ "nInserted" : 1 })登録済みドキュメントの確認
find()メソッドを実行すると、コレクション内のすべてのドキュメントを一覧表示できます。
> db.demo636.find();
上記クエリの出力結果は以下のとおりです。
{ "_id" : ObjectId("5e9c127b6c954c74be91e6d2"), "id" : 1 }
{ "_id" : ObjectId("5e9c127e6c954c74be91e6d3"), "id" : 2 }
{ "_id" : ObjectId("5e9c127f6c954c74be91e6d4"), "id" : 3 }
{ "_id" : ObjectId("5e9c12816c954c74be91e6d5"), "id" : 4 }
{ "_id" : ObjectId("5e9c12836c954c74be91e6d6"), "id" : 5 }
{ "_id" : ObjectId("5e9c12896c954c74be91e6d7"), "id" : 6 }mapReduce()で1つおきのドキュメントを出力するクエリ
続いて、mapReduce()を使用して、1つおきのドキュメント(この例ではidが奇数のもの)だけを出力します。ポイントは、scopeオプションでカウンター変数を定義し、マップ関数内で各ドキュメントの処理ごとにカウントしながら条件判定を行う点です。
> db.demo636.mapReduce(
... function () {
... oddCounter++;
... var id = this._id;
... delete this._id;
... if ( oddCounter % d != 0 )
... emit(id, this);
... },
... function() {},
... {
... "scope": { "oddCounter": 0, "d": 2 },
... "out": { "inline": 1 }
... }
... )クエリのポイント
- scope:グローバル変数としてカウンター(oddCounter)と割り切るための値(d)を定義しています。dの値を変更すれば、「2つおき」「3つおき」といった間隔での抽出も自由に調整可能です。
- マップ関数:ドキュメントが処理されるたびにoddCounterをインクリメントし、oddCounter % d の結果が0でない場合にのみemit()で出力対象としています。これにより、1つおきのドキュメントだけが結果に含まれます。
- out: { inline: 1 }:結果を新しいコレクションへ保存せず、そのままインラインで返却します。
実行結果
クエリを実行すると、以下のようにidが奇数のドキュメント(1つおきのドキュメント)のみが出力されます。
{
"results" : [
{
"_id" : ObjectId("5e9c127b6c954c74be91e6d2"),
"value" : {
"id" : 1
}
},
{
"_id" : ObjectId("5e9c127f6c954c74be91e6d4"),
"value" : {
"id" : 3
}
},
{
"_id" : ObjectId("5e9c12836c954c74be91e6d6"),
"value" : {
"id" : 5
}
}
],
"timeMillis" : 29,
"counts" : {
"input" : 6,
"emit" : 3,
"reduce" : 0,
"output" : 3
},
"ok" : 1
}まとめ
mapReduce()のscopeオプションとカウンターを組み合わせることで、コレクションから任意の間隔でドキュメントを抽出できます。なお、mapReduce()はMongoDB 5.0以降では非推奨となっており、最新バージョンではアグリゲーションパイプライン($groupや$mergeなど)を使った同様の実装が推奨されています。既存システムでの保守や学習目的には、本記事の手法が参考になるでしょう。
-
MongoDB 4でドキュメントをソートし、特定の1つのフィールドだけを表示する方法
MongoDB 4でドキュメントを並べ替えるには、sort()メソッドを使用します。さらに、ソートした特定の1つのフィールドのみを表示したい場合は、プロジェクション(射影)を組み合わせて、表示したいフィールドに「1」を設定します。この記事では、実際のコード例を使って手順を順番に解説していきます。1. サンプルコレクションの作成まず、insertOne()メソッドを使って、テスト用のコレクション「demo611」にドキュメントを登録します。> db.demo611.insertOne({Name:Chris}); { acknowledged : true, insertedI
-
MongoDBでコレクション内のドキュメントの各フィールドを数式を使って更新する方法
コレクション内のドキュメントの各フィールドを数式(計算式)で一括更新したい場合は、MongoDBの update() メソッドに $mul 演算子と全位置演算子 $[] を組み合わせて使用します。本記事では、配列内のすべての要素に対して特定のフィールドの値を乗算で更新する具体的な手順を解説します。サンプルコレクションの作成まず、insertOne() メソッドを使って、ドキュメントを含むコレクションを作成します。> db.demo749.insertOne({details:[{id:1,a:10},{id:2,a:5},{id:3,a:20}]}); { acknowledge