MongoDBでグループごとに最大属性を持つドキュメントを取得する方法($sortと$groupの活用)
MongoDBのコレクションから、グループごとに特定の属性が最大値となるドキュメントを取得したい場合、$sort演算子と$groupステージを組み合わせた集計パイプラインを使用します。
この記事では、実際にサンプルデータを作成しながら、その具体的な手順をわかりやすく解説します。
1. サンプルコレクションの作成
まずは動作確認用に、学生情報を格納したコレクション「maxAttributePerGroup」を作成し、ドキュメントを挿入していきます。insertOne()メソッドを使って、以下のように4件のドキュメントを登録します。
> db.maxAttributePerGroup.insertOne({"StudentFirstName":"John","StudentLastName":"Smith","StudentAge":29,"StudentId":10});
{
"acknowledged" : true,
"insertedId" : ObjectId("5c76ee341e9c5dd6f1f78277")
}
> db.maxAttributePerGroup.insertOne({"StudentFirstName":"Carol","StudentLastName":"Taylor","StudentAge":19,"StudentId":10});
{
"acknowledged" : true,
"insertedId" : ObjectId("5c76ee4e1e9c5dd6f1f78278")
}
> db.maxAttributePerGroup.insertOne({"StudentFirstName":"Adam","StudentLastName":"Smith","StudentAge":34,"StudentId":20});
{
"acknowledged" : true,
"insertedId" : ObjectId("5c76ee631e9c5dd6f1f78279")
}
> db.maxAttributePerGroup.insertOne({"StudentFirstName":"Bob","StudentLastName":"Taylor","StudentAge":58,"StudentId":20});
{
"acknowledged" : true,
"insertedId" : ObjectId("5c76ee791e9c5dd6f1f7827a")
}このサンプルデータでは、StudentIdが10のグループにJohn(29歳)とCarol(19歳)、StudentIdが20のグループにAdam(34歳)とBob(58歳)が属しています。ここから、各グループで最も年齢が高い学生のドキュメントを取得することが目標です。
2. 登録したドキュメントの確認
find()メソッドを使って、コレクション内のすべてのドキュメントを表示してみましょう。
> db.maxAttributePerGroup.find().pretty();
出力結果
{
"_id" : ObjectId("5c76ee341e9c5dd6f1f78277"),
"StudentFirstName" : "John",
"StudentLastName" : "Smith",
"StudentAge" : 29,
"StudentId" : 10
}
{
"_id" : ObjectId("5c76ee4e1e9c5dd6f1f78278"),
"StudentFirstName" : "Carol",
"StudentLastName" : "Taylor",
"StudentAge" : 19,
"StudentId" : 10
}
{
"_id" : ObjectId("5c76ee631e9c5dd6f1f78279"),
"StudentFirstName" : "Adam",
"StudentLastName" : "Smith",
"StudentAge" : 34,
"StudentId" : 20
}
{
"_id" : ObjectId("5c76ee791e9c5dd6f1f7827a"),
"StudentFirstName" : "Bob",
"StudentLastName" : "Taylor",
"StudentAge" : 58,
"StudentId" : 20
}4件のドキュメントが正しく登録されていることが確認できました。
3. グループごとの最大値ドキュメントを取得するクエリ
それでは本題です。aggregate()メソッドを使い、まず$sortで「StudentId」を昇順、「StudentAge」を降順に並べ替えます。その後、$groupでStudentIdごとにまとめ、$first演算子によって各グループの先頭(=年齢が最大)のドキュメントの値を取得します。
> db.maxAttributePerGroup.aggregate([
{"$sort":{"StudentId":1,"StudentAge":-1}},
{$group:{
"_id":"$StudentId",
"StudentAge":{"$first":"$StudentAge"},
"StudentFirstName":{"$first":"$StudentFirstName"},
"StudentLastName":{"$first":"$StudentLastName"}
}} ]).pretty();出力結果
{
"_id" : 20,
"StudentAge" : 58,
"StudentFirstName" : "Bob",
"StudentLastName" : "Taylor"
}
{
"_id" : 10,
"StudentAge" : 29,
"StudentFirstName" : "John",
"StudentLastName" : "Smith"
}クエリの仕組み解説
このクエリが期待どおりに動作するポイントは、処理の順序にあります。
① $sortによる並べ替え: 「{"StudentId":1, "StudentAge":-1}」という指定により、StudentIdを昇順に、同じStudentIdの中ではStudentAgeを降順(大きい順)にソートします。これにより、各グループ内で年齢が最も大きいドキュメントが必ず先頭に来るようになります。
② $groupによるグループ化: 「_id: "$StudentId"」でStudentIdごとにドキュメントをグループ化します。
③ $firstによる値の取得: グループ化後の各グループでは、ソート済みの先頭ドキュメント(=年齢最大のドキュメント)の値が$firstで取得されます。そのため、StudentIdが10のグループでは29歳のJohn、StudentIdが20のグループでは58歳のBobが抽出されるのです。
なお、最小値を持つドキュメントを取得したい場合は、$sortのStudentAgeを「1」(昇順)に変更するだけで対応できます。このテクニックは、売上ランキングや最新レコードの抽出など、さまざまな場面で応用できる便利なパターンなので、ぜひ覚えておきましょう。
-
MongoDBの$or演算子で複数条件に一致するドキュメントを取得する方法
はじめにMongoDBでは、$or演算子を使うことで、複数の条件のうちいずれか1つでも一致したドキュメントを取得できます。本記事では、サンプルコレクションを作成し、$or演算子を用いたOR条件検索の具体的な方法を解説します。サンプルコレクションの作成まず、insertOne()メソッドを使って、demo711というコレクションにドキュメントを挿入していきましょう。> db.demo711.insertOne({Name:"John","Marks":75,Age:21,status:"Active"}); { "
-
MongoDBでコレクション内のドキュメントの各フィールドを数式を使って更新する方法
コレクション内のドキュメントの各フィールドを数式(計算式)で一括更新したい場合は、MongoDBの update() メソッドに $mul 演算子と全位置演算子 $[] を組み合わせて使用します。本記事では、配列内のすべての要素に対して特定のフィールドの値を乗算で更新する具体的な手順を解説します。サンプルコレクションの作成まず、insertOne() メソッドを使って、ドキュメントを含むコレクションを作成します。> db.demo749.insertOne({details:[{id:1,a:10},{id:2,a:5},{id:3,a:20}]}); { acknowledge