MongoDBの$project演算子でフィールドを射影(プロジェクション)する方法
MongoDBの集計パイプライン(aggregation pipeline)において、ドキュメントから特定のフィールドを射影(プロジェクション)して出力形式を整形したい場合は、$project ステージを使用します。$project を使うと、表示するフィールドの選択だけでなく、$cond や $ifNull などの演算子を組み合わせて、条件に応じた値の変換や代替値の設定も可能です。
この記事では、実際にコレクションを作成し、$project を使ってネストされたフィールドを条件付きで射影する方法を解説します。
1. サンプルコレクションの作成
まず、insertOne() メソッドを使って、ドキュメントを含むコレクションを作成します。ここでは学生の名前と点数情報を持つ3件のドキュメントを挿入します。なお、3件目のドキュメントは意図的に異なるフィールド名(Score1、Score2)を使用しています。
> db.demo439.insertOne(
... {
... "Name" : "Chris",
... "MarksInformation" : {
... "Marks1" : 67,
... "Marks2" : 45,
... "Marks3" : 78
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e77833abbc41e36cc3caeab")
}
> db.demo439.insertOne(
... {
... "Name" : "David",
... "MarksInformation" : {
... "Marks1" : 50,
... "Marks2" : 57,
... "Marks3" : 68
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e77833abbc41e36cc3caeac")
}
> db.demo439.insertOne(
... {
... "Name" : "Bob",
... "MarksInformation" : {
... "Score1" : 65,
... "Score2" : 71
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e77833bbbc41e36cc3caead")
}2. find()メソッドですべてのドキュメントを表示
find() メソッドを使って、コレクション内のすべてのドキュメントを表示します。
> db.demo439.find();
このクエリを実行すると、次のような出力が得られます。
{ "_id" : ObjectId("5e77833abbc41e36cc3caeab"), "Name" : "Chris", "MarksInformation" : { "Marks1" : 67, "Marks2" : 45, "Marks3" : 78 } }
{ "_id" : ObjectId("5e77833abbc41e36cc3caeac"), "Name" : "David", "MarksInformation" : { "Marks1" : 50, "Marks2" : 57, "Marks3" : 68 } }
{ "_id" : ObjectId("5e77833bbbc41e36cc3caead"), "Name" : "Bob", "MarksInformation" : { "Score1" : 65, "Score2" : 71 } }3. $projectでフィールドを射影するクエリ
続いて、$project を使用してフィールドを射影するクエリを見ていきましょう。ポイントは以下の通りです。
- $ifNull: フィールドが存在しない場合やnullの場合に、代わりのデフォルト値(ここでは0)を返します。
- $eq: 値が等しいかどうかを比較します。ここでは「Marks1が0(=存在しない)かどうか」を判定しています。
- $cond: 条件分岐を行います。条件がtrueなら第2引数の値、falseなら第3引数の値を返します。
つまり、「Marks1」フィールドが存在しない場合は「Score1」の値を代わりに使い、存在する場合はそのまま「Marks1」の値を出力する、という処理を実現しています。
> db.demo439.aggregate({
... $project: {
... "Name" : 1,
... "Marks1": { $cond: [ { $eq:[ { $ifNull: [ "$MarksInformation.Marks1", 0 ] }, 0 ] }, { $ifNull: [ "$MarksInformation.Score1", 0 ] }, "$MarksInformation.Marks1" ] },
... "Marks2": { $cond: [ { $eq:[ { $ifNull: [ "$MarksInformation.Marks2", 0 ] }, 0 ] }, { $ifNull: [ "$MarksInformation.Score2", 0 ] }, "$MarksInformation.Marks2" ] },
... "Marks3": { $cond: [ { $eq:[ { $ifNull: [ "$MarksInformation.Marks3", 0] }, 0 ] }, { $ifNull: [ "$MarksInformation.Score3", 0 ] }, "$MarksInformation.Marks3" ] }
... }})4. 実行結果
上記の集計クエリを実行すると、次のような出力が得られます。
{ "_id" : ObjectId("5e77833abbc41e36cc3caeab"), "Name" : "Chris", "Marks1" : 67, "Marks2" : 45, "Marks3" : 78 }
{ "_id" : ObjectId("5e77833abbc41e36cc3caeac"), "Name" : "David", "Marks1" : 50, "Marks2" : 57, "Marks3" : 68 }
{ "_id" : ObjectId("5e77833bbbc41e36cc3caead"), "Name" : "Bob", "Marks1" : 65, "Marks2" : 71, "Marks3" : 0 }結果のポイント
出力結果に注目すると、Bobのドキュメントには元々「Marks1」「Marks2」というフィールドが存在せず、「Score1」「Score2」のみが存在していました。しかし、$project の条件付き射影によって、Score1とScore2の値(65と71)がそれぞれMarks1とMarks2として出力されています。また、Marks3もScore3も存在しないため、デフォルト値の0が出力されています。
このように$project を $cond・$ifNull・$eq と組み合わせることで、スキーマが不統一なドキュメントでも、出力形式を統一した整形済みデータとして取得できます。フィールド名が揺れているデータセットを扱う際に非常に便利なテクニックなので、ぜひ活用してみてください。
-
MongoDBで特定のフィールドを条件にドキュメントを検索する方法($or演算子の使い方)
MongoDBでは、複数のフィールドにまたがる条件を指定してドキュメントを検索できます。本記事では、$or 演算子を使って「名前(Name)」または「国名(CountryName)」のいずれかに一致するドキュメントを取得する方法を、実際のコード例とともに解説します。1. コレクションの作成とドキュメントの挿入まず、insertOne() メソッドを使用してサンプル用のコレクションを作成し、ドキュメントを挿入します。> db.demo371.insertOne({Name:David,CountryName:US}); { acknowledged : true, insert
-
MongoDBの_idフィールドを非表示にする方法
MongoDBの_idフィールドを非表示にする方法MongoDBでは、find()メソッドでドキュメントを検索すると、デフォルトで_idフィールド(ObjectId)が必ず結果に含まれます。しかし、射影(プロジェクション)という仕組みを使えば、この_idフィールドを非表示にし、必要なフィールドだけを取得することが可能です。本記事では、具体的な手順をサンプルコード付きで解説します。1. コレクションとドキュメントの作成まず、サンプル用のコレクションを作成し、ドキュメントを挿入します。> db.demo575.insertOne({id:101, Information:{Name:&quo