近年、ウェブアプリケーションやモバイルアプリが扱うデータ量は爆発的に増加し、その種類も多様化しています。従来のリレーショナルデータベース(RDBMS)だけでは対応が難しいケースも増えてきました。そこで注目されているのが、NoSQL(Not Only SQL)データベースです。
NoSQLデータベースは、RDBMSとは異なるデータモデルやアーキテクチャを採用することで、高いスケーラビリティ(拡張性)や柔軟性を実現しています。その中でも特に人気が高く、広く利用されているのがMongoDBです。
このブログ記事では、NoSQLデータベースの代表格であるMongoDBについて、その基本的な概念から具体的な使い方まで、入門者向けにわかりやすく解説していきます。RDBMSしか触ったことがない方でも理解できるよう、順を追って丁寧に説明しますので、ぜひ最後までお付き合いください!😊
まず、MongoDBを理解する上で欠かせない「NoSQLデータベース」とは何か、そして従来のRDBMSと何が違うのかを見ていきましょう。
1.1. RDBMS (Relational Database Management System)
MySQL, PostgreSQL, Oracle Database, SQL Server などが代表的なRDBMSです。データをテーブル(表)形式で管理し、行(レコード)と列(カラム)で構成されます。データ構造は事前にスキーマとして厳密に定義する必要があり、データ間の関連性はリレーション(外部キーなど)で表現します。データの整合性を保つためのACID特性(原子性、一貫性、独立性、永続性)を重視しており、複雑なトランザクション処理に適しています。問い合わせ言語にはSQL (Structured Query Language) を使用します。
1.2. NoSQL (Not Only SQL) データベース
NoSQLは、RDBMSが苦手とするような、大量データの高速処理や柔軟なデータ構造への対応を目的として登場しました。SQLを使わない、あるいはSQL以外の問い合わせ言語も利用できるデータベースの総称です。「Not Only SQL」という名前の通り、SQLを完全に否定するものではありません。
NoSQLデータベースは、そのデータモデルによっていくつかの種類に分類されます。
- ドキュメント指向データベース: JSON/BSONのようなドキュメント形式でデータを格納します。(例: MongoDB, Couchbase)
- キー・バリュー型データベース: 単純なキーと値のペアでデータを格納します。(例: Redis, Memcached)
- カラム指向データベース: 行ではなく列単位でデータを格納し、特定の列に対する集計などが高速です。(例: Cassandra, HBase)
- グラフ型データベース: ノード(点)とエッジ(線)でデータ間の関係性を表現するのに特化しています。(例: Neo4j, Amazon Neptune)
1.3. RDBMSとNoSQLの主な違いまとめ
項目 | RDBMS | NoSQL (MongoDBの場合) |
---|---|---|
データモデル | テーブル(行と列) | ドキュメント(JSON/BSON形式) |
スキーマ | 厳密(事前に定義が必要) | 柔軟(スキーマレス、動的に変更可能) |
スケーラビリティ | スケールアップ(サーバー性能向上)が主 | スケールアウト(サーバー台数増加)が得意 |
データ整合性 | 強い整合性 (ACID準拠) | 結果整合性 (BASE特性) を許容する場合が多い(MongoDBは単一ドキュメントではACID準拠) |
問い合わせ言語 | SQL | 独自のAPIやクエリ言語(MongoDB Query Language) |
得意な処理 | 複雑なトランザクション、関連性の強いデータの扱い | 大量データの読み書き、柔軟なデータ構造、分散処理 |
どちらが良い・悪いというわけではなく、用途に応じて適切なデータベースを選択することが重要です。近年では、RDBMSとNoSQLを組み合わせて利用するポリグロット・パーシステンスという考え方も一般的になっています。
MongoDBは、数あるNoSQLデータベースの中でもドキュメント指向データベースに分類され、非常に人気があります。その主な特徴を見ていきましょう。
2.1. ドキュメント指向
MongoDBは、データをドキュメントという単位で管理します。このドキュメントは、JSON (JavaScript Object Notation) に似たBSON (Binary JSON) という形式で格納されます。BSONはJSONの表現力に加え、バイナリデータ型や日付型など、より多くのデータ型をサポートしています。
例:ユーザー情報を表すドキュメント
{
"_id": ObjectId("60d5ecf1d4a7b8a7a6d5c8f1"), // 一意なID (自動生成)
"name": "山田 太郎",
"email": "yamada@example.com",
"age": 30,
"address": { // ネストされたドキュメント
"prefecture": "東京都",
"city": "千代田区"
},
"tags": ["developer", "mongodb", "入門"], // 配列
"registered_at": ISODate("2023-01-15T10:00:00Z") // 日付型
}
このように、階層構造を持つデータをそのままの形で格納できるため、アプリケーションのオブジェクト構造とデータベースの構造が近くなり、開発効率が向上します。RDBMSのように、オブジェクトを複数のテーブルに分割して格納し、JOINを使って結合するといった手間が軽減されます。
2.2. スキーマレス(柔軟なスキーマ)
MongoDBはスキーマレスであると言われますが、正確には柔軟なスキーマを持つ、という意味合いが強いです。RDBMSのように事前にテーブルの構造(カラム名やデータ型)を厳密に定義する必要がありません。同じコレクション(RDBMSのテーブルに相当)内にあるドキュメントでも、それぞれ異なるフィールドを持つことができます。
// ドキュメント1
{ "name": "佐藤 次郎", "age": 25 }
// ドキュメント2 (同じコレクション内)
{ "name": "鈴木 花子", "email": "suzuki@example.com", "hobbies": ["読書", "旅行"] }
これにより、アプリケーションの要件変更に素早く対応でき、アジャイル開発との親和性が高いです。ただし、完全に無秩序にデータを格納すると後々管理が大変になるため、ある程度のスキーマ設計(バリデーションルールなど)を行うことが推奨されます。MongoDBにはスキーマバリデーション機能も用意されています。
2.3. 高いスケーラビリティ
MongoDBは、スケールアウト(水平分散)を容易に行えるように設計されています。データ量やアクセス負荷が増加した場合、サーバーのスペックを上げる(スケールアップ)だけでなく、サーバーの台数を増やすことで性能を向上させることができます。
- レプリケーション: データを複数のサーバーに複製することで、可用性(耐障害性)と読み取り性能を向上させます。プライマリサーバーに障害が発生しても、セカンダリサーバーが処理を引き継ぎます。
- シャーディング: 大量のデータを複数のサーバー(シャード)に分割して格納することで、書き込み性能やデータ容量の制限を克服します。
これらの機能により、大規模なサービスにも対応可能なスケーラビリティを実現しています。
2.4. 豊富なクエリ言語とインデックス
MongoDBは、単純なキー・バリューストアとは異なり、豊富なクエリ機能を提供しています。
- フィールドの値による検索(範囲指定、正規表現なども可能)
- ネストされたドキュメントや配列内の要素に対する検索
- 地理空間クエリ
- 全文検索
また、RDBMSと同様にインデックスをサポートしており、クエリのパフォーマンスを大幅に向上させることができます。シングルフィールドインデックス、複合インデックス、地理空間インデックス、テキストインデックスなど、様々な種類のインデックスを作成できます。
2.5. 集計フレームワーク (Aggregation Pipeline)
MongoDBには、Aggregation Pipelineという強力な集計機能があります。これは、複数のステージ(処理段階)をパイプラインのように連結して、複雑なデータ集計や変換を行う仕組みです。RDBMSのGROUP BY句や集計関数、さらにはサブクエリやJOINに相当するような処理を、柔軟かつ効率的に実行できます。
これにより、バッチ処理やデータ分析など、様々な用途でMongoDBを活用できます。
MongoDBを実際に使い始めるための環境構築方法には、いくつかの選択肢があります。
3.1. ローカル環境へのインストール
お使いのOS (Windows, macOS, Linux) にMongoDB Community Serverを直接インストールする方法です。開発や学習目的で手軽に始められます。
公式サイトのドキュメントに従ってインストールを進めてください。 MongoDB Community Server ダウンロード
インストール後、`mongod` (データベースサーバープロセス) を起動し、`mongosh` (MongoDB Shell) というコマンドラインツールを使って接続します。
# mongod を起動 (方法はOSにより異なる)
# 例: brew services start mongodb-community (macOS Homebrew)
# mongosh で接続
mongosh
3.2. Dockerを利用する
DockerコンテナとしてMongoDBを起動する方法です。環境の分離が容易で、セットアップやクリーンアップが簡単に行えます。
# MongoDBの公式Dockerイメージを取得
docker pull mongo
# MongoDBコンテナを起動 (-d: バックグラウンド実行, --name: コンテナ名, -p: ポートフォワーディング)
docker run -d --name my-mongo -p 27017:27017 mongo
# 起動したコンテナの mongosh に接続
docker exec -it my-mongo mongosh
3.3. MongoDB Atlas (クラウドサービス) を利用する
MongoDB社が提供するフルマネージドなクラウドデータベースサービスです。インフラ管理の手間が不要で、無料枠 (Free Tier) も用意されているため、すぐに試すことができます。スケーリングやバックアップなども簡単に行え、本番環境での利用にも適しています。
アカウント登録後、Web上のUIからクラスターを作成し、接続情報を取得して `mongosh` や各種ドライバから接続します。
手軽に試したい場合は MongoDB Atlas の無料枠がおすすめです。ローカルでの開発がメインなら、ローカルインストールや Docker が良いでしょう。
MongoDBを操作する上で、基本的な構成要素を理解しておく必要があります。
- データベース (Database): 複数のコレクションを格納するコンテナです。RDBMSのデータベースに相当します。1つのMongoDBサーバーインスタンスで複数のデータベースを管理できます。
- コレクション (Collection): ドキュメントの集まりです。RDBMSのテーブルに相当しますが、スキーマは固定されません。通常、関連性の高いドキュメントを同じコレクションに格納します。
- ドキュメント (Document): MongoDBにおけるデータの基本単位です。BSON形式で、フィールドと値のペアで構成されます。RDBMSの行(レコード)に相当します。各ドキュメントはコレクション内で一意な `_id` フィールドを持ちます(指定しない場合は自動生成されます)。
- フィールド (Field): ドキュメント内のキー(名前)です。RDBMSの列(カラム)に似ていますが、ドキュメントごとに異なるフィールドを持つことができます。
- BSON (Binary JSON): JSONを拡張したバイナリ形式のデータフォーマットです。JSONのデータ型に加え、日付、バイナリデータ、数値型(Int32, Int64, Decimal128など)などをサポートし、効率的な格納と高速なスキャンを実現します。
これらの関係を図で示すと(図は描けませんがイメージしてください!)、以下のようになります。
`mongosh` での基本操作例:
// 現在のデータベースを表示
show dbs
// 使用するデータベースを切り替え (存在しない場合は新規作成される)
use myNewDatabase
// 現在使用中のデータベースを表示
db
// 現在のデータベース内のコレクション一覧を表示
show collections
// 'users' コレクションにドキュメントを1件挿入 (コレクションが存在しない場合は自動作成)
db.users.insertOne({ name: "田中 実", age: 35 })
// 'users' コレクション内の全ドキュメントを表示
db.users.find()
データベース操作の基本であるCRUD (Create, Read, Update, Delete) をMongoDBでどのように行うか見ていきましょう。ここでは `mongosh` を使った例を示します。
5.1. Create (作成・挿入)
新しいドキュメントをコレクションに追加します。
`insertOne()`: 1件のドキュメントを挿入
// 'products' コレクションに1件挿入
db.products.insertOne({
name: "ラップトップPC",
price: 150000,
category: "Electronics",
tags: ["pc", "work"],
stock: 50
})
成功すると、挿入されたドキュメントの `_id` を含む結果が返されます。
{
acknowledged: true,
insertedId: ObjectId("60d5f1a1b1c9d4a8e7d6f2a2")
}
`insertMany()`: 複数のドキュメントを一度に挿入
// 'products' コレクションに複数件挿入
db.products.insertMany([
{ name: "キーボード", price: 8000, category: "Accessories", tags: ["pc", "input"], stock: 100 },
{ name: "マウス", price: 5000, category: "Accessories", tags: ["pc", "input"], stock: 150 },
{ name: "Webカメラ", price: 7000, category: "Accessories", tags: ["pc", "online"], stock: 80, resolution: "1080p" } // 他のドキュメントとフィールドが異なってもOK
])
成功すると、挿入された各ドキュメントの `_id` のリストを含む結果が返されます。
{
acknowledged: true,
insertedIds: [
ObjectId("60d5f2b1c1c9d4a8e7d6f2a3"),
ObjectId("60d5f2b1c1c9d4a8e7d6f2a4"),
ObjectId("60d5f2b1c1c9d4a8e7d6f2a5")
]
}
5.2. Read (読み取り・検索)
コレクションからドキュメントを検索します。
`find()`: 条件に一致する複数のドキュメントを検索
// 'products' コレクションの全ドキュメントを取得
db.products.find()
// category が "Accessories" のドキュメントを検索
db.products.find({ category: "Accessories" })
// price が 10000 未満のドキュメントを検索 (比較演算子 $lt: less than)
db.products.find({ price: { $lt: 10000 } })
// price が 5000 以上 10000 未満のドキュメントを検索 ($gte: greater than or equal)
db.products.find({ price: { $gte: 5000, $lt: 10000 } })
// category が "Accessories" かつ stock が 100 未満のドキュメントを検索 (暗黙的なAND)
db.products.find({ category: "Accessories", stock: { $lt: 100 } })
// category が "Electronics" または price が 5000 以下のドキュメントを検索 (論理演算子 $or)
db.products.find({
$or: [
{ category: "Electronics" },
{ price: { $lte: 5000 } } // $lte: less than or equal
]
})
// tags 配列に "pc" が含まれるドキュメントを検索
db.products.find({ tags: "pc" })
// tags 配列に "pc" と "input" の両方が含まれるドキュメントを検索 ($all)
db.products.find({ tags: { $all: ["pc", "input"] } })
// name が "ラップトップ" で始まるドキュメントを検索 (正規表現 $regex)
db.products.find({ name: { $regex: "^ラップトップ" } })
// ネストされたドキュメントのフィールドで検索 (ドット記法)
// address.prefecture が "東京都" のユーザーを検索 (users コレクションと仮定)
// db.users.find({ "address.prefecture": "東京都" })
クエリ演算子(一部)
MongoDBは豊富なクエリ演算子を提供しています。
- 比較演算子: `$eq` (等しい), `$ne` (等しくない), `$gt` (より大きい), `$gte` (以上), `$lt` (より小さい), `$lte` (以下), `$in` (いずれかに一致), `$nin` (いずれにも一致しない)
- 論理演算子: `$and` (かつ), `$or` (または), `$not` (否定), `$nor` (どちらでもない)
- 要素演算子: `$exists` (フィールドが存在するか), `$type` (フィールドの型)
- 配列演算子: `$all` (全ての要素を含む), `$elemMatch` (配列要素が条件に一致), `$size` (配列の要素数)
- 評価演算子: `$regex` (正規表現), `$text` (全文検索), `$where` (JavaScript式)
- 地理空間演算子: `$geoWithin`, `$geoIntersects`, `$near`, `$nearSphere`
`findOne()`: 条件に一致する最初の1件のドキュメントを検索
// category が "Electronics" の最初の1件を取得
db.products.findOne({ category: "Electronics" })
// _id で検索 (ObjectId はそのまま指定可能)
db.products.findOne({ _id: ObjectId("60d5f1a1b1c9d4a8e7d6f2a2") })
`findOne()` は `find()` と異なり、カーソルではなく単一のドキュメント(または `null`)を返します。
プロジェクション: 結果に含めるフィールドを指定
`find()` や `findOne()` の第2引数で、結果に含めるフィールド(または除外するフィールド)を指定できます。`1` で含める、`0` で除外します。`_id` はデフォルトで含まれるため、除外したい場合は明示的に `_id: 0` を指定します。
// name と price のみを取得 (_id もデフォルトで含まれる)
db.products.find({ category: "Accessories" }, { name: 1, price: 1 })
// name と price のみを取得し、_id は除外する
db.products.find({ category: "Accessories" }, { name: 1, price: 1, _id: 0 })
// stock フィールドを除外し、それ以外をすべて取得
db.products.find({ category: "Accessories" }, { stock: 0 })
結果の整形: `sort()`, `limit()`, `skip()`
`find()` の結果に対して、並び替え、件数制限、スキップを行うことができます。
// price の昇順で並び替え (1: 昇順, -1: 降順)
db.products.find().sort({ price: 1 })
// price の降順で並び替え
db.products.find().sort({ price: -1 })
// price の降順で並び替え、最初の3件を取得
db.products.find().sort({ price: -1 }).limit(3)
// price の昇順で並び替え、最初の2件をスキップして、次の3件を取得 (ページネーションなどに利用)
db.products.find().sort({ price: 1 }).skip(2).limit(3)
5.3. Update (更新)
既存のドキュメントを変更します。
`updateOne()`: 条件に一致する最初の1件のドキュメントを更新
第1引数に更新対象を特定するクエリ、第2引数に更新内容を指定します。更新内容には更新演算子(`$set`, `$inc` など)を使用します。
// name が "マウス" のドキュメントの price を 5500 に、stock を 140 に更新 ($set: フィールドの値を設定)
db.products.updateOne(
{ name: "マウス" },
{ $set: { price: 5500, stock: 140 } }
)
// name が "キーボード" のドキュメントの stock を 10 増やす ($inc: 値を増減)
db.products.updateOne(
{ name: "キーボード" },
{ $inc: { stock: 10 } }
)
// name が "ラップトップPC" のドキュメントに新しいフィールド 'updated_at' を追加 ($set はフィールド追加にも使える)
db.products.updateOne(
{ name: "ラップトップPC" },
{ $set: { updated_at: new Date() } }
)
// name が "ラップトップPC" のドキュメントの tags 配列に "new" を追加 ($push: 配列に要素を追加)
db.products.updateOne(
{ name: "ラップトップPC" },
{ $push: { tags: "new" } }
)
// name が "ラップトップPC" のドキュメントから resolution フィールドを削除 ($unset: フィールドを削除)
db.products.updateOne(
{ name: "ラップトップPC" },
{ $unset: { resolution: "" } } // 値は何でもよいが、空文字列が一般的
)
`updateMany()`: 条件に一致するすべてのドキュメントを更新
使い方は `updateOne()` と同じですが、条件に一致するすべてのドキュメントが更新対象となります。
// category が "Accessories" のすべてのドキュメントに 'last_checked' フィールドを追加
db.products.updateMany(
{ category: "Accessories" },
{ $set: { last_checked: new Date() } }
)
// stock が 0 のすべてのドキュメントの status を "out_of_stock" に設定
db.products.updateMany(
{ stock: 0 },
{ $set: { status: "out_of_stock" } }
)
`replaceOne()`: 条件に一致する最初の1件のドキュメントを完全に置換
第2引数に指定した新しいドキュメントで、既存のドキュメントを完全に置き換えます。更新演算子(`$set`など)は使わず、新しいドキュメントそのものを指定します。`_id` フィールドは変更できません。
// name が "Webカメラ" のドキュメントを新しい内容で置き換え
db.products.replaceOne(
{ name: "Webカメラ" },
{
name: "高画質Webカメラ", // name を変更
price: 8500,
category: "Accessories",
tags: ["pc", "online", "streaming"], // tags を変更
stock: 75,
resolution: "4K" // resolution を変更
// 元々あった _id はそのまま維持される
}
)
指定したフィールド以外の元々あったフィールドはすべて削除されます。意図しないデータ消失を防ぐため、通常は `$set` などの更新演算子を使った `updateOne()` や `updateMany()` の利用が推奨されます。
主な更新演算子(一部)
- フィールド演算子: `$set` (値設定/追加), `$unset` (フィールド削除), `$inc` (数値増減), `$mul` (数値乗算), `$rename` (フィールド名変更), `$min` (値がより小さい場合のみ更新), `$max` (値がより大きい場合のみ更新), `$currentDate` (現在日時を設定)
- 配列演算子: `$push` (末尾に追加), `$pop` (先頭/末尾削除), `$pull` (条件に合う要素削除), `$pullAll` (指定要素すべて削除), `$addToSet` (存在しない場合のみ追加)
5.4. Delete (削除)
コレクションからドキュメントを削除します。
`deleteOne()`: 条件に一致する最初の1件のドキュメントを削除
// name が "マウス" のドキュメントを1件削除
db.products.deleteOne({ name: "マウス" })
`deleteMany()`: 条件に一致するすべてのドキュメントを削除
// category が "Obsolete" のドキュメントをすべて削除
db.products.deleteMany({ category: "Obsolete" })
// コレクション内のすべてのドキュメントを削除 (空のクエリ {} を指定)
// !!注意!! この操作は元に戻せません!
// db.products.deleteMany({})
特に `deleteMany({})` を実行すると、コレクション内のすべてのデータが失われます。実行前に必ず条件を確認し、必要であればバックアップを取得してください。
データ量が増えてくると、`find()` などの検索クエリの速度が低下することがあります。RDBMSと同様に、MongoDBでもインデックスを作成することで、特定のフィールドに対する検索パフォーマンスを大幅に向上させることができます。
6.1. なぜインデックスが必要か?
インデックスがない場合、MongoDBはクエリに一致するドキュメントを見つけるために、コレクション内のすべてのドキュメントをスキャン(コレクションスキャン)する必要があります。これはデータ量が多い場合には非常に非効率です。
インデックスは、特定のフィールド(または複数のフィールド)の値を、その値を持つドキュメントへのポインタと共に、効率的に検索できるデータ構造(通常はB-Tree)に格納します。これにより、MongoDBはコレクション全体をスキャンする代わりに、インデックスを使って目的のドキュメントを素早く見つけることができます。
6.2. インデックスの作成 (`createIndex()`)
`createIndex()` メソッドを使ってインデックスを作成します。
// 'products' コレクションの 'name' フィールドに昇順インデックスを作成
db.products.createIndex({ name: 1 }) // 1: 昇順, -1: 降順
// 'category' フィールドに昇順、'price' フィールドに降順の複合インデックスを作成
db.products.createIndex({ category: 1, price: -1 })
// ネストされたフィールド 'address.city' にインデックスを作成
// db.users.createIndex({ "address.city": 1 })
// ユニークインデックスを作成 (同じ値を持つドキュメントの挿入/更新を禁止)
db.users.createIndex({ email: 1 }, { unique: true })
// TTLインデックスを作成 (指定時間経過後にドキュメントを自動削除。ログなどに利用)
// 'createdAt' フィールドの値から 1時間 (3600秒) 後に削除
// db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
6.3. インデックスの確認と削除
// 'products' コレクションのインデックス一覧を表示
db.products.getIndexes()
// 特定のインデックスを削除 (インデックス名を指定)
// インデックス名は getIndexes() で確認できます (例: "name_1")
db.products.dropIndex("name_1")
// すべての非 _id インデックスを削除
db.products.dropIndexes()
6.4. インデックスの注意点
- インデックスは検索を高速化しますが、書き込み(挿入、更新、削除)のパフォーマンスをわずかに低下させます。データが変更されるたびにインデックスも更新する必要があるためです。
- インデックスはディスク容量とメモリを消費します。
- 頻繁に検索されるフィールドや、ソートに使われるフィールドにインデックスを作成するのが効果的です。
- やみくもにインデックスを作成するのではなく、クエリの実行計画 (`explain()`) を分析し、ボトルネックとなっている箇所を特定した上で、適切なインデックスを作成することが重要です。
// クエリの実行計画を確認
db.products.find({ category: "Electronics" }).sort({ price: 1 }).explain("executionStats")
MongoDBのAggregation Pipeline (集計パイプライン) は、データを段階的に処理し、複雑な集計や変換を行うための強力なフレームワークです。SQLの `GROUP BY`、集計関数、さらにはサブクエリやJOINに似た操作を実現できます。
7.1. パイプラインの仕組み
Aggregation Pipelineは、複数のステージ (Stage) で構成されます。コレクション内のドキュメントは、最初のステージに入力され、そのステージでの処理結果が次のステージへの入力となります。このように、ドキュメントがパイプラインを流れながら、段階的に変換・集計されていきます。
`db.collection.aggregate()` メソッドを使用し、引数にステージの配列を渡します。
7.2. 主なステージ
- `$match`: ドキュメントをフィルタリングします。`find()` のクエリと同じ構文を使用します。パイプラインの早い段階で使用すると、処理対象のドキュメント数を減らし効率的です。
- `$group`: 指定したキーでドキュメントをグループ化し、各グループに対して集計処理(合計、平均、最大、最小など)を行います。`_id` フィールドでグループ化のキーを指定します。
- `$project`: 出力ドキュメントのフィールド reshaping(フィールドの追加、削除、名前変更、値の計算)を行います。`find()` のプロジェクションに似ていますが、より高機能です。
- `$sort`: ドキュメントを並び替えます。
- `$limit`: 出力ドキュメント数を制限します。
- `$skip`: 指定した数のドキュメントをスキップします。
- `$unwind`: 配列フィールドを展開し、配列の各要素に対してドキュメントを複製します。
- `$lookup`: 別のコレクションとJOIN(左外部結合)のような操作を行います。
- `$out`: パイプラインの結果を新しいコレクションに出力します。
- `$merge`: パイプラインの結果を既存または新規のコレクションにマージ(挿入、更新、置換)します。
7.3. 集計例
例1:カテゴリごとの商品数と平均価格を計算する
db.products.aggregate([
{
$group: {
_id: "$category", // category フィールドでグループ化
count: { $sum: 1 }, // 各グループのドキュメント数をカウント
averagePrice: { $avg: "$price" } // 各グループの price の平均値を計算
}
},
{
$sort: { averagePrice: -1 } // 平均価格の降順で並び替え
}
])
結果の例:
[
{ _id: 'Electronics', count: 1, averagePrice: 150000 },
{ _id: 'Accessories', count: 3, averagePrice: 7166.666666666667 }
]
例2:価格が10000円以上の商品のタグを集計し、タグごとの出現回数を求める
db.products.aggregate([
{
$match: { price: { $gte: 10000 } } // priceが10000以上の商品をフィルタリング
},
{
$unwind: "$tags" // tags 配列を展開
},
{
$group: {
_id: "$tags", // 展開されたタグでグループ化
count: { $sum: 1 } // 各タグの出現回数をカウント
}
},
{
$sort: { count: -1 } // 出現回数の降順で並び替え
}
])
結果の例 (元のデータによる):
[
{ _id: 'pc', count: 1 },
{ _id: 'work', count: 1 },
{ _id: 'new', count: 1 }
// ... 他のタグ
]
Aggregation Pipelineは非常に強力で多機能ですが、最初は少し複雑に感じるかもしれません。簡単なステージから試していき、徐々に複雑なパイプラインを構築していくと良いでしょう。
この入門記事では、NoSQLデータベースの基本から始まり、MongoDBの魅力的な特徴、環境構築、基本的な概念、そして最も重要なCRUD操作、さらには検索を高速化するインデックス、高度なデータ集計を行うAggregation Pipelineについて解説しました。
MongoDBの主な利点まとめ ✅
- 柔軟なスキーマ: 変化に強いアプリケーション開発が可能。
- 高いスケーラビリティ: 大規模データ・高負荷に対応しやすい(スケールアウト)。
- ドキュメント指向: アプリケーションのオブジェクト構造と親和性が高い。
- 豊富なクエリ機能とインデックス: 多様な検索ニーズに対応し、パフォーマンスも確保。
- 強力な集計機能: 複雑なデータ分析やバッチ処理が可能。
MongoDBは、Webアプリケーションのバックエンド、IoTデータの蓄積、ログ分析、コンテンツ管理など、非常に幅広い分野で活用されています。
次のステップへ 🚀
MongoDBの世界は非常に奥が深いです。この入門記事で基本を掴んだら、さらに以下のトピックについて学習を進めることをお勧めします。
- 各種ドライバの使い方: Python (PyMongo), Node.js (mongodb), Java, Go など、お使いのプログラミング言語からMongoDBを操作する方法。
- スキーマ設計のベストプラクティス: 柔軟なスキーマを活かしつつ、効率的で管理しやすいデータ構造を設計する方法(エンベディング vs リファレンスなど)。
- 高度なインデックス戦略: 複合インデックス、部分インデックス、テキストインデックス、地理空間インデックスなどの活用法。
- Aggregation Pipeline の詳細: より多くのステージや演算子、パイプラインの最適化。
- レプリケーションとシャーディング: 高可用性とスケーラビリティを実現するための設定と運用。
- セキュリティ設定: 認証、認可、暗号化など。
- MongoDB Atlas の活用: クラウドサービスならではの機能(サーバーレス、全文検索サービス、データレイクなど)。
学習のためのリソースも豊富にあります。
- 🔗 MongoDB 公式ドキュメント (最も信頼できる情報源)
- 🔗 MongoDB University (無料のオンラインコース)
- 🔗 MongoDB Community Forums (質問や議論ができるフォーラム)
ぜひ実際にMongoDBを触りながら、そのパワフルさと柔軟性を体験してみてください。Happy Coding! 😊
コメント