はい、承知いたしました。MongoDBの初心者向けに、よく使う基本コマンドを詳細に解説する記事を作成します。約5000語を目指し、各コマンドの目的、使い方、具体的な例、そして関連する概念を分かりやすく説明します。
【初心者向け】MongoDB よく使う基本コマンド詳細解説
はじめに:MongoDBの世界へようこそ
データベースと聞くと、多くの方がExcelのような表形式のデータを思い浮かべるかもしれません。これは「リレーショナルデータベース(RDB)」という形式で、データを厳格なスキーマ(構造)に基づいてテーブルに格納し、テーブル間を関連付けて管理します。Oracle Database、MySQL、PostgreSQLなどが代表的です。
一方で、近年注目されているのが「NoSQLデータベース」です。NoSQLは「Not only SQL」の略で、「SQLだけではない」様々な形式のデータベースを指します。NoSQLデータベースは、RDBのような厳格なスキーマを持たず、多様なデータを柔軟に扱うことができます。その中でも特に人気が高いのが、今回解説するMongoDBです。
MongoDBとは?
MongoDBは、ドキュメント指向型のNoSQLデータベースです。データをJSON(JavaScript Object Notation)に似たBSON(Binary JSON)形式の「ドキュメント」として格納します。ドキュメントは、キーと値のペアの集まりで、RDBにおける行(レコード)に相当します。複数のドキュメントが集まったものが「コレクション」と呼ばれ、RDBにおけるテーブルに相当します。そして、複数のコレクションが集まったものが「データベース」となります。
- RDB: データベース → テーブル → 行
- MongoDB: データベース → コレクション → ドキュメント
MongoDBの大きな特徴は以下の通りです。
- 柔軟なスキーマ: ドキュメントごとに含まれるフィールドが異なっていても構いません。開発中にデータの構造変更が容易です。
- 高い拡張性: スケールアウト(サーバーを増やして性能を向上させる)が比較的容易です。シャーディングという機能を使って、大規模なデータも分散して管理できます。
- パフォーマンス: ドキュメント内に関連データを埋め込むことで、RDBのようなJOIN操作を減らし、データの読み書きを高速化できます。
- 豊富な機能: ACIDトランザクション(複数操作のまとまりを保証する仕組み)、集計フレームワーク、地理空間インデックスなど、モダンなアプリケーション開発に必要な多くの機能を備えています。
なぜMongoDBを学ぶのか?
ウェブアプリケーション、モバイルアプリケーション、IoT、ビッグデータ分析など、現代の様々なシステムでMongoDBが利用されています。特に、以下のようなケースでMongoDBは真価を発揮します。
- データ構造が頻繁に変わる、あるいは多様なデータを扱う必要があるプロジェクト。
- 高いスケーラビリティが求められるサービス。
- アジャイル開発のように、迅速な開発とイテレーションが必要な場合。
この柔軟性と拡張性から、多くの企業や開発者がMongoDBを採用しています。MongoDBを使いこなすことは、現代のソフトウェア開発において強力なスキルとなるでしょう。
この記事では、MongoDBを使い始める上で必要となる基本的なコマンドと概念を、初心者の方にも理解できるよう詳細に解説していきます。MongoDB Shell (mongosh) を使って実際にコマンドを実行しながら学ぶことを想定しています。
MongoDB Shell (mongosh) への接続
MongoDBの操作は、専用のインタラクティブなシェルである mongosh を使うのが一般的です。まずは mongosh に接続してみましょう。
MongoDBサーバーの起動
ローカル環境にMongoDBをインストール済みであれば、通常は以下のコマンドでサーバーを起動します。(OSやインストール方法によって異なる場合があります。)
bash
mongod
mongosh での接続
サーバーが起動したら、別のターミナルウィンドウを開き、以下のコマンドで mongosh を起動します。
bash
mongosh
特に設定を変更していなければ、デフォルトで localhost:27017 のMongoDBサーバーに接続されます。接続に成功すると、以下のようなプロンプトが表示されます。
test>
これは、現在 test という名前のデータベースを選択していることを示しています。プロンプトに続けてコマンドを入力していきます。
データベースとコレクションの操作
MongoDBでの作業は、まず操作対象の「データベース」を選択し、その中の「コレクション」に対して行います。ここでは、データベースとコレクションの基本的な操作コマンドを学びましょう。
データベースを選択する: use
操作したいデータベースを選択するには use コマンドを使います。
javascript
use <database_name>
例として、myNewDatabase という名前のデータベースを選択してみましょう。
javascript
use myNewDatabase
実行すると、以下のような出力が表示され、プロンプトが変化します。
changed to db myNewDatabase
myNewDatabase>
これで、以降の操作はこの myNewDatabase に対して行われます。
ポイント: use コマンドで指定したデータベースが存在しない場合、そのデータベースは実際に作成されるのではなく、その名前で参照できるようになるだけです。データベースは、その中に最初のドキュメントが挿入されたり、コレクションが作成されたりした時点で物理的に作成されます。
現在選択しているデータベースを確認する: db
現在自分がどのデータベースを操作しているかを確認するには、単に db と入力します。
javascript
db
実行すると、現在選択中のデータベース名が表示されます。
myNewDatabase
存在するデータベースの一覧を表示する: show dbs
MongoDBサーバー上に存在するデータベースの一覧を表示するには show dbs コマンドを使います。
javascript
show dbs
実行例:
admin 40.00 KiB
config 73.74 KiB
local 73.74 KiB
myNewDatabase 0.00 B
test 40.00 KiB
admin, config, local はMongoDBの管理目的で使用される組み込みデータベースです。test はデフォルトで接続した際に選択されるデータベースです。myNewDatabase が先ほど use コマンドで参照したデータベースです。サイズが 0.00 B となっているのは、まだ何もデータが含まれていないためです。
コレクションを作成する: db.createCollection()
MongoDBでは、通常、ドキュメントを挿入する際に指定したコレクションが存在しなければ、自動的にそのコレクションが作成されます。そのため、明示的にコレクションを作成する機会は少ないかもしれません。しかし、特定のオプション(例: 固定サイズコレクション)を指定して作成したい場合などに createCollection() メソッドを使用します。
javascript
db.createCollection("<collection_name>")
例として、users という名前のコレクションを作成してみましょう。
javascript
db.createCollection("users")
実行結果:
{ ok: 1 }
ok: 1 はコマンドが成功したことを意味します。
存在するコレクションの一覧を表示する: show collections または db.getCollectionNames()
選択中のデータベース内に存在するコレクションの一覧を表示するには show collections コマンドまたは db.getCollectionNames() メソッドを使用します。どちらも同じ目的で使用できます。
javascript
show collections
または
javascript
db.getCollectionNames()
myNewDatabase で users コレクションを作成した後に実行すると、以下のような結果が得られます。
users
ドキュメントの基本操作 (CRUD)
データベースの操作の最も中心となるのが、ドキュメントに対する操作です。これはRDBにおけるレコード(行)の操作にあたります。ドキュメントの操作は、以下の4つの基本操作に分けられます。
- Create (作成・挿入)
- Read (読み取り・検索)
- Update (更新)
- Delete (削除)
これらの操作をまとめて「CRUD」と呼びます。それぞれの操作について詳しく見ていきましょう。
C – Create (挿入)
新しいドキュメントをコレクションに追加します。
単一ドキュメントの挿入: insertOne()
一つのドキュメントをコレクションに挿入するには insertOne() メソッドを使います。
javascript
db.<collection_name>.insertOne(<document>)
<document> には、挿入したいドキュメントをBSON形式(JavaScriptオブジェクトのリテラル形式で記述)で指定します。
例:users コレクションに新しいユーザー情報ドキュメントを挿入する。
javascript
db.users.insertOne(
{
name: "山田 太郎",
age: 30,
email: "[email protected]",
address: {
city: "Tokyo",
zip: "100-0001"
},
interests: ["programming", "music"]
}
)
実行結果:
{
acknowledged: true,
insertedId: ObjectId("...") // 自動生成された_id
}
acknowledged: true は操作が成功したことを示します。insertedId は、挿入されたドキュメントに自動的に割り当てられた一意な識別子 (_id フィールドの値) です。
_id フィールドについて:
MongoDBでは、全てのドキュメントに一意な _id フィールドが必要です。ドキュメントを挿入する際に _id を指定しなかった場合、MongoDBが自動的に ObjectId 型の一意な値を生成して割り当てます。この _id は、通常、そのドキュメントを識別するための主キーとして機能します。
複数ドキュメントの挿入: insertMany()
複数のドキュメントを一度に挿入するには insertMany() メソッドを使います。引数には、挿入したいドキュメントの配列を指定します。
javascript
db.<collection_name>.insertMany([<document1>, <document2>, ...])
例:複数のユーザー情報ドキュメントを挿入する。
javascript
db.users.insertMany([
{
name: "佐藤 花子",
age: 25,
email: "[email protected]",
interests: ["reading", "travel"]
},
{
name: "田中 一郎",
age: 45,
email: "[email protected]",
address: {
city: "Osaka",
zip: "530-0001"
},
interests: ["cooking"]
},
{
name: "鈴木 次郎",
age: 35,
email: "[email protected]" // ageフィールドがないドキュメント
}
])
実行結果:
{
acknowledged: true,
insertedIds: {
'0': ObjectId("..."),
'1': ObjectId("..."),
'2': ObjectId("...")
}
}
複数の _id が insertedIds オブジェクトとして返されます。
注意点:
insertMany() はデフォルトでは ordered: true で実行されます。これは、配列の先頭から順番にドキュメントを挿入し、途中でエラーが発生した場合、それ以降のドキュメントの挿入は中断されるという挙動です。エラーが発生しても可能な限り多くのドキュメントを挿入したい場合は、オプションで { ordered: false } を指定します。
R – Read (読み取り・検索)
コレクションに格納されているドキュメントを検索して取得します。MongoDBの検索は非常に柔軟です。
全ドキュメントの検索: find()
コレクション内の全てのドキュメントを取得するには、引数なしで find() メソッドを使います。
javascript
db.<collection_name>.find()
例:users コレクションの全てのドキュメントを取得する。
javascript
db.users.find()
実行結果:
[
{
_id: ObjectId("..."),
name: "山田 太郎",
age: 30,
email: "[email protected]",
address: { city: "Tokyo", zip: "100-0001" },
interests: [ "programming", "music" ]
},
{
_id: ObjectId("..."),
name: "佐藤 花子",
age: 25,
email: "[email protected]",
interests: [ "reading", "travel" ]
},
{
_id: ObjectId("..."),
name: "田中 一郎",
age: 45,
email: "[email protected]",
address: { city: "Osaka", zip: "530-0001" },
interests: [ "cooking" ]
},
{
_id: ObjectId("..."),
name: "鈴木 次郎",
age: 35,
email: "[email protected]"
}
]
find() メソッドは、実際にはすぐにドキュメントを全て取得するのではなく、「カーソル」と呼ばれるオブジェクトを返します。mongosh は便宜上、カーソルの最初の数件を表示してくれますが、より多くの結果を扱う場合は、カーソルを操作する必要があります。(詳細については、より進んだトピックになります。)
条件を指定した検索: find({ <query_document> })
特定の条件を満たすドキュメントのみを取得するには、find() メソッドの第一引数に「クエリドキュメント」を指定します。クエリドキュメントは、検索条件をキーと値のペアで記述したオブジェクトです。
基本的なクエリ形式:
javascript
db.<collection_name>.find({ <field1>: <value1>, <field2>: <value2>, ... })
これは「field1がvalue1と等しく、かつfield2がvalue2と等しいドキュメント」を検索します。
例:name が “山田 太郎” のドキュメントを検索する。
javascript
db.users.find({ name: "山田 太郎" })
実行結果:
[
{
_id: ObjectId("..."),
name: "山田 太郎",
age: 30,
email: "[email protected]",
address: { city: "Tokyo", zip: "100-0001" },
interests: [ "programming", "music" ]
}
]
様々な条件指定方法:
-
ネストされたドキュメント内のフィールド: ドット記法 (
.) を使います。例:
address.cityが “Tokyo” のドキュメントを検索する。javascript
db.users.find({ "address.city": "Tokyo" }) -
配列内の要素: 配列に特定の値が含まれているドキュメントを検索します。
例:
interests配列に “programming” が含まれているドキュメントを検索する。javascript
db.users.find({ interests: "programming" })例:
interests配列に “reading” または “travel” が含まれているドキュメントを検索する。javascript
db.users.find({ interests: { $in: ["reading", "travel"] } })
$in演算子は、フィールドの値がいずれかの値と一致する場合にマッチします。 -
比較演算子: 特定の値よりも大きい、小さいなどの条件を指定するには、比較演算子を使います。演算子は
$ <operator>の形式で指定します。主な比較演算子:
*$eq: 等しい(: valueと同じ)
*$ne: 等しくない
*$gt: より大きい (Greater Than)
*$gte: 以上 (Greater Than or Equal To)
*$lt: より小さい (Less Than)
*$lte: 以下 (Less Than or Equal To)例:
ageが30より大きいドキュメントを検索する。javascript
db.users.find({ age: { $gt: 30 } })例:
ageが30以上、かつ40以下のドキュメントを検索する。(複合条件の指定)javascript
db.users.find({ age: { $gte: 30, $lte: 40 } })
このように、同じフィールドに対して複数の演算子を使う場合は、それらをオブジェクト内に記述します。 -
論理演算子: 複数の条件を組み合わせるには論理演算子を使います。
主な論理演算子:
*$and: 全ての条件を満たす (AND)
*$or: いずれかの条件を満たす (OR)
*$not: 条件を満たさない (NOT)
*$nor: 全ての条件を満たさない (NOT OR)例:
ageが30より大きい、またはaddress.cityが “Osaka” のドキュメントを検索する。javascript
db.users.find({ $or: [ { age: { $gt: 30 } }, { "address.city": "Osaka" } ] })
$orや$andは、条件ドキュメントの配列を値として取ります。例:
ageが30より大きい、かつinterestsに “programming” が含まれるドキュメントを検索する。javascript
db.users.find({ $and: [ { age: { $gt: 30 } }, { interests: "programming" } ] })
フィールドをカンマで区切って記述した{ age: { $gt: 30 }, interests: "programming" }は、暗黙的に$and条件となります。$andを明示的に使うのは、同じフィールドに対して複数の条件を指定したい場合などです。(例:$and: [{ x: 1 }, { x: { $gt: 5 } }]は意味をなさないが、異なるフィールドの複雑な組み合わせに$andを使うことはある) -
フィールドの存在チェック: 特定のフィールドが存在するかどうかで検索します。
$exists: フィールドの存在をチェック
例:
addressフィールドが存在するドキュメントを検索する。javascript
db.users.find({ address: { $exists: true } })例:
addressフィールドが存在しないドキュメントを検索する。javascript
db.users.find({ address: { $exists: false } }) -
データ型チェック: 特定のデータ型のフィールドを検索します。
$type: データ型をチェック
例:
ageフィールドが数値型 (Number) のドキュメントを検索する。(数値型にはDouble(1),Int32(16),Int64(18) など複数の型がありますが、ここでは型エイリアスnumberを使うのが便利です)javascript
db.users.find({ age: { $type: "number" } }) // 型番号 (例: 16) を指定することも可能BSONタイプと対応する番号やエイリアスはMongoDBのドキュメントを参照してください。
単一ドキュメントの検索: findOne()
条件にマッチする最初のドキュメントだけを取得したい場合は findOne() メソッドを使います。これは、ユニークなキーで検索する場合など、結果が一つだけであることが分かっている場合に便利です。
javascript
db.<collection_name>.findOne({ <query_document> })
引数なしで findOne() を実行すると、コレクション内の最初のドキュメントを取得します。
例:_id が特定の ObjectId のドキュメントを取得する。
javascript
db.users.findOne({ _id: ObjectId("...") }) // ... には実際のObjectIdを指定
findOne() はカーソルを返さず、直接ドキュメントオブジェクトまたは null(マッチするドキュメントがない場合)を返します。
検索結果の整形と制限
find() メソッドで取得した結果に対して、さらに様々な操作を連鎖させて適用することができます。これは、find() がカーソルを返すという特性を利用したものです。
-
プロジェクション (表示フィールドの選択):
find()の第二引数にプロジェクションドキュメントを指定することで、取得するフィールドを限定できます。これにより、ネットワーク帯域やメモリ使用量を節約できます。javascript
db.<collection_name>.find(<query>, { <field1>: 1, <field2>: 1, ... })フィールド名をキーに、値に
1を指定するとそのフィールドが表示されます。0を指定するとそのフィールドは非表示になります。ただし、_idフィールドはデフォルトで表示されるため、非表示にしたい場合は明示的に_id: 0と指定する必要があります。1と0を混在させることは、_idを除くフィールド間ではできません(どちらか一方のパターンのみ使用可)。例:全てのドキュメントについて、
nameとemailフィールドのみを表示し、_idは非表示にする。javascript
db.users.find({}, { name: 1, email: 1, _id: 0 })実行結果(山田 太郎の場合):
[
{ name: "山田 太郎", email: "[email protected]" },
...
] -
件数制限:
limit()取得するドキュメントの最大件数を指定します。javascript
db.<collection_name>.find(<query>).limit(<number>)例:年齢が30歳以上のユーザーのうち、最初の2件を取得する。
javascript
db.users.find({ age: { $gte: 30 } }).limit(2) -
スキップ:
skip()結果の先頭から指定した数のドキュメントをスキップします。これは、ページネーション(一覧表示をページ分けすること)に利用できます。javascript
db.<collection_name>.find(<query>).skip(<number>)例:年齢が30歳以上のユーザーのうち、最初の2件をスキップして、次の3件を取得する。(
limit()と組み合わせてページネーション)javascript
db.users.find({ age: { $gte: 30 } }).skip(2).limit(3) -
ソート:
sort()検索結果を指定したフィールドで並べ替えます。javascript
db.<collection_name>.find(<query>).sort({ <field1>: <order1>, <field2>: <order2>, ... })<order>に1を指定すると昇順、-1を指定すると降順になります。複数のフィールドを指定すると、最初のフィールドでソートし、同順位の場合は次のフィールドでソート、というように適用されます。例:年齢の昇順でユーザーを取得する。
javascript
db.users.find().sort({ age: 1 })例:年齢の降順でソートし、同じ年齢の場合は名前(
name)の昇順でソートする。javascript
db.users.find().sort({ age: -1, name: 1 })
これらのメソッド(limit(), skip(), sort() など)は、find() から返されるカーソルオブジェクトのメソッドとして呼び出されます。複数のメソッドを組み合わせて使用する場合、その順序は実行結果に影響します。(通常は find().sort().skip().limit() の順で使用することが多いです。)
件数取得: countDocuments() / estimatedDocumentCount()
条件にマッチするドキュメントの数を取得するには countDocuments() メソッドを使います。全ドキュメントの概算件数を高速に取得したい場合は estimatedDocumentCount() を使います。
javascript
db.<collection_name>.countDocuments({ <query> }) // 条件指定あり
db.<collection_name>.estimatedDocumentCount() // 条件指定なし、高速だが概算
例:年齢が30歳以上のユーザー数を取得する。
javascript
db.users.countDocuments({ age: { $gte: 30 } })
例:コレクション全体のドキュメント数を概算で取得する。
javascript
db.users.estimatedDocumentCount()
U – Update (更新)
既存のドキュメントの内容を変更します。更新操作では、どのドキュメントを更新するか(フィルター)と、どのように更新するか(更新オペレーター)を指定します。
単一ドキュメントの更新: updateOne()
条件にマッチする最初のドキュメントを更新するには updateOne() メソッドを使います。
javascript
db.<collection_name>.updateOne(
{ <filter> }, // 更新対象を特定するクエリ
{ <update> }, // 更新内容を指定するオペレーター
{ <options> } // オプション (例: upsert)
)
更新内容の指定には、更新オペレーターと呼ばれる特殊なフィールドを使います。
主な更新オペレーター:
-
$set: フィールドの値を設定します。フィールドが存在しない場合は新しく作成されます。例:
nameが “山田 太郎” のドキュメントのageを31に、emailを新しいメールアドレスに更新する。javascript
db.users.updateOne(
{ name: "山田 太郎" },
{ $set: { age: 31, email: "[email protected]" } }
)例:
addressフィールドがないドキュメントにaddressフィールドを追加する。(例: 鈴木 次郎)javascript
db.users.updateOne(
{ name: "鈴木 次郎" },
{ $set: { address: { city: "Nagoya", zip: "460-0001" } } }
) -
$inc: 数値フィールドの値を指定した量だけ増減させます。(Increment)例:
nameが “山田 太郎” のドキュメントのageを1歳増やす。javascript
db.users.updateOne(
{ name: "山田 太郎" },
{ $inc: { age: 1 } } // -1 を指定すれば減らせる
) -
$unset: フィールドを削除します。例:
nameが “田中 一郎” のドキュメントからaddressフィールドを削除する。javascript
db.users.updateOne(
{ name: "田中 一郎" },
{ $unset: { address: "" } } // 値は何でも良いが "" を使うのが一般的
) -
$push: 配列フィールドに要素を追加します。例:
nameが “佐藤 花子” のドキュメントのinterests配列に “cooking” を追加する。javascript
db.users.updateOne(
{ name: "佐藤 花子" },
{ $push: { interests: "cooking" } }
) -
$pull: 配列フィールドから特定の値を削除します。例:
nameが “山田 太郎” のドキュメントのinterests配列から “music” を削除する。javascript
db.users.updateOne(
{ name: "山田 太郎" },
{ $pull: { interests: "music" } }
)
upsert オプション: updateOne() のオプションとして { upsert: true } を指定すると、フィルターにマッチするドキュメントが存在しない場合、指定したフィルターと更新内容を組み合わせて新しいドキュメントを挿入します。
例:email が “[email protected]” のユーザーを探し、存在すれば更新、存在しなければ新規作成する。(ここでは簡単のため $set のみで構成していますが、$setOnInsert オペレーターと組み合わせて使うのが一般的です)
javascript
db.users.updateOne(
{ email: "[email protected]" },
{ $set: { name: "新規 ユーザー", age: 20 } },
{ upsert: true }
)
複数ドキュメントの更新: updateMany()
条件にマッチする全てのドキュメントを更新するには updateMany() メソッドを使います。
javascript
db.<collection_name>.updateMany(
{ <filter> }, // 更新対象を特定するクエリ
{ <update> } // 更新内容を指定するオペレーター
)
例:年齢が30歳以上の全てのユーザーの status フィールドを “active” に設定する。
javascript
db.users.updateMany(
{ age: { $gte: 30 } },
{ $set: { status: "active" } }
)
更新操作の結果確認
updateOne() や updateMany() の実行結果オブジェクトには、操作に関する情報が含まれています。
javascript
{
acknowledged: true, // 操作が成功したか
insertedId: null, // upsert: true で新規挿入された場合の_id
matchedCount: 1, // フィルターにマッチしたドキュメント数
modifiedCount: 1, // 実際に更新されたドキュメント数
upsertedId: null // upsert: true で新規挿入された場合の_id (insertOneの結果と同じ意味)
}
matchedCount は更新対象となったドキュメント数、modifiedCount は更新オペレーターによって実際に値が変更されたドキュメント数を示します。例えば、$setで現在の値と同じ値を設定した場合、$set自体は成功しますが、modifiedCount は増加しません。
D – Delete (削除)
コレクションからドキュメントを削除します。
単一ドキュメントの削除: deleteOne()
条件にマッチする最初のドキュメントを削除するには deleteOne() メソッドを使います。
javascript
db.<collection_name>.deleteOne({ <filter> })
例:name が “田中 一郎” のドキュメントを削除する。
javascript
db.users.deleteOne({ name: "田中 一郎" })
複数ドキュメントの削除: deleteMany()
条件にマッチする全てのドキュメントを削除するには deleteMany() メソッドを使います。
javascript
db.<collection_name>.deleteMany({ <filter> })
例:年齢が40歳以上の全てのドキュメントを削除する。
javascript
db.users.deleteMany({ age: { $gte: 40 } })
注意点: フィルターに空のドキュメント {} を指定すると、コレクション内の全てのドキュメントが削除されます。実行時には十分注意してください。
javascript
db.users.deleteMany({}) // コレクション内の全てのドキュメントを削除
コレクション自体の削除: drop()
コレクションに格納されているドキュメントだけでなく、コレクション自体を削除するには drop() メソッドを使います。
javascript
db.<collection_name>.drop()
例:users コレクションを削除する。
javascript
db.users.drop()
実行結果:
javascript
true // 成功した場合
コレクションを削除すると、その中に含まれていた全てのドキュメントと、そのコレクションに関連付けられていたインデックスも全て削除されます。
データベース自体の削除: db.dropDatabase()
現在選択中のデータベースと、その中に含まれる全てのコレクション、ドキュメント、インデックスを削除するには db.dropDatabase() メソッドを使います。
javascript
db.dropDatabase()
例:現在選択中の myNewDatabase を削除する。
javascript
db.dropDatabase()
実行結果:
javascript
{ dropped: 'myNewDatabase', ok: 1 }
データベースを削除すると、その中のデータは全て失われます。実行時には細心の注意が必要です。
インデックス
データ量が増えてくると、検索(Read操作)のパフォーマンスが重要になります。RDBと同様に、MongoDBでも「インデックス」を作成することで検索速度を大幅に向上させることができます。インデックスは、特定のフィールドの値を効率的に検索できるように整理されたデータ構造です。
インデックスとは?
例えるなら、本の巻末にある索引のようなものです。索引があれば、読みたいキーワードが本のどこに書いてあるかをページをめくって探すのではなく、索引を見て素早く目的のページにたどり着けます。データベースのインデックスも同様に、特定のフィールドの値から対応するドキュメントを素早く見つけ出せるようにします。
インデックスは、データが追加、更新、削除されるたびに更新されるため、書き込み(Create, Update, Delete操作)にはオーバーヘッドがかかります。しかし、頻繁に検索されるフィールドに適切なインデックスを作成することで、全体的なパフォーマンスが向上することが多いです。
MongoDBは、コレクション作成時に _id フィールドに対してユニークなインデックスを自動的に作成します。
インデックスの作成: createIndex()
特定のフィールドにインデックスを作成するには createIndex() メソッドを使います。
javascript
db.<collection_name>.createIndex(
{ <field1>: <order1>, <field2>: <order2>, ... }, // インデックスキー
{ <options> } // オプション (例: unique, sparse, name)
)
インデックスキーとして指定するドキュメントでは、インデックスを作成したいフィールド名をキーに、値として 1(昇順)または -1(降順)を指定します。単一フィールドだけでなく、複数のフィールドを組み合わせた複合インデックスも作成できます。
例:age フィールドに昇順のインデックスを作成する。
javascript
db.users.createIndex({ age: 1 })
例:email フィールドにユニーク(一意)インデックスを作成する。(同じメールアドレスを持つドキュメントが複数存在できなくなります)
javascript
db.users.createIndex({ email: 1 }, { unique: true })
例:address.city と age の複合インデックスを作成する。(まず address.city でソートされ、次に age でソートされるイメージ)
javascript
db.users.createIndex({ "address.city": 1, age: -1 })
インデックスの効果:
インデックスを作成すると、そのフィールドや複合インデックスに含まれるフィールドを使った検索、ソート、範囲指定などが高速化される可能性が高まります。特に、検索条件(find() のフィルター)、ソート条件(sort())、集計パイプラインの $match や $sort ステージなどでインデックスが利用されます。
作成済みのインデックスを確認する: getIndexes()
コレクションに作成されているインデックスの一覧を確認するには getIndexes() メソッドを使います。
javascript
db.<collection_name>.getIndexes()
例:users コレクションのインデックスを確認する。
javascript
db.users.getIndexes()
実行結果:
[
{
v: 2,
key: { _id: 1 },
name: '_id_'
},
{
v: 2,
key: { age: 1 },
name: 'age_1' // createIndexで自動生成された名前
}
]
_id フィールドのインデックス(_id_ という名前)は自動的に作成されます。age_1 は先ほど createIndex({ age: 1 }) で作成したインデックスです。name フィールドを指定してインデックスを作成することも可能です。
インデックスを削除する: dropIndex()
不要になったインデックスを削除するには dropIndex() メソッドを使います。削除したいインデックスの名前またはインデックスキーを指定します。
javascript
db.<collection_name>.dropIndex("<index_name>")
または
javascript
db.<collection_name>.dropIndex({ <field1>: <order1>, ... }) // インデックスキーを指定
例:age フィールドのインデックス(名前が age_1)を削除する。
javascript
db.users.dropIndex("age_1")
例:address.city と age の複合インデックスをキー指定で削除する。
javascript
db.users.dropIndex({ "address.city": 1, age: -1 })
インデックスを削除すると、そのインデックスを利用していたクエリのパフォーマンスが低下する可能性があります。
クエリの実行計画を確認する: explain()
特定のクエリがどのように実行されるか、どのインデックスが利用されるかなどを詳細に確認するには、explain() メソッドを使います。これはパフォーマンスチューニングにおいて非常に重要なツールです。
javascript
db.<collection_name>.find(<query>).explain("<mode>")
// または
db.<collection_name>.aggregate(<pipeline>).explain("<mode>")
<mode> には queryPlanner (デフォルト), executionStats, allPlansExecution などがあります。まずは executionStats モードで実行するのが一般的です。
例:年齢が30歳以上のユーザーを検索するクエリの実行計画を確認する。
javascript
db.users.find({ age: { $gte: 30 } }).explain("executionStats")
実行結果には、どのインデックスが選ばれたか (winningPlan.inputStage.indexName)、スキャンされたドキュメント数 (executionStats.totalDocsExamined)、返されたドキュメント数 (executionStats.totalDocsReturned)、実行時間などが含まれます。totalDocsExamined が totalDocsReturned に比べて極端に大きい場合(特にインデックスがない場合)、コレクション全体をスキャン(Collection Scan)している可能性があり、インデックス作成を検討する手がかりになります。
集計 (Aggregation Framework) – 基本
MongoDBの集計フレームワークは、データを変換、集計、分析するための強力な機能です。RDBの GROUP BY や JOIN、複雑な計算などを行うことができます。初心者向けとしては、最も基本的な使い方として、データをフィルタリングし、特定のキーでグループ化して集計する流れを学びましょう。
集計操作は aggregate() メソッドを使用し、データの処理手順を定義した「パイプライン」を引数に指定します。パイプラインは、ステージと呼ばれる操作の配列で構成されます。データはパイプラインの各ステージを順番に通過し、最終的な結果が得られます。
javascript
db.<collection_name>.aggregate([
{ <stage1> },
{ <stage2> },
...
])
基本的な集計パイプラインステージ:
-
$match: 入力ドキュメントをフィルタリングします。find()メソッドのクエリと同じ形式で条件を指定します。パイプラインの早い段階で$matchを使うことで、後続のステージで処理するデータ量を減らし、効率を向上させることができます。例:年齢が30歳以上のユーザーだけを対象とする。
javascript
{ $match: { age: { $gte: 30 } } } -
$group: 入力ドキュメントを指定したキーでグループ化し、グループごとに集計演算子を使って計算を行います。RDBのGROUP BYに相当します。構文:
{ $group: { _id: <expression>, <outputField1>: { <accumulator1>: <expression1> }, ... } }
_idにはグループ化のキーを指定します。nullを指定すると全てのドキュメントを一つのグループとして扱います。<expression>にはフィールド名($field_nameの形式)などを指定します。
主な集計演算子(Accumulators):
*$sum: 合計値を計算します。
*$avg: 平均値を計算します。
*$count: グループ内のドキュメント数を数えます。
*$min: 最小値を取得します。
*$max: 最大値を取得します。例:
ageでグループ化し、各年齢のユーザー数をカウントする。javascript
{ $group: { _id: "$age", count: { $count: {} } } } // または count: { $sum: 1 }
結果のドキュメントは{ _id: <age>, count: <count> }の形式になります。_idはグループ化のキーの値です。 -
$project: 入力ドキュメントから、必要なフィールドを選択したり、フィールド名を変更したり、新しいフィールドを追加したりします。RDBのSELECT句に似ています。例:
nameとemailフィールドだけを残し、_idは非表示にする。javascript
{ $project: { name: 1, email: 1, _id: 0 } }例:
nameとageフィールドを使い、新しいフィールドname_with_ageを作成する。javascript
{ $project: { name_with_age: { $concat: ["$name", " (", { $toString: "$age" }, ")" ] } } }
$field_nameはフィールドの値を参照します。$concatや$toStringは集計演算子です。 -
$sort: ドキュメントを指定したフィールドでソートします。find().sort()と同じ構文です。例:年齢の昇順でソートする。
javascript
{ $sort: { age: 1 } } -
$limit: パイプラインを通過するドキュメント数を制限します。find().limit()と同じです。例:最初の5件のみを取得する。
javascript
{ $limit: 5 } -
$skip: パイプラインを通過するドキュメントの先頭から指定した数をスキップします。find().skip()と同じです。例:最初の10件をスキップする。
javascript
{ $skip: 10 }
基本的な集計例
例:年齢が30歳以上のユーザーを対象に、居住都市 (address.city) ごとのユーザー数をカウントし、ユーザー数の多い順に表示する。
- 年齢が30歳以上のドキュメントをフィルタリング (
$match) - 居住都市 (
address.city) でグループ化し、各グループのドキュメント数をカウント ($group) - カウント数 (
count) の降順でソート ($sort)
javascript
db.users.aggregate([
{
$match: { age: { $gte: 30 } }
},
{
$group: { _id: "$address.city", count: { $count: {} } }
},
{
$sort: { count: -1 }
}
])
実行結果例:
[
{ _id: 'Tokyo', count: 1 },
{ _id: 'Osaka', count: 0 }, //田中一郎はage>=30だがaddress削除済みのためnullまたはundefinedグループへ
{ _id: null, count: 1 } //鈴木次郎などaddressフィールドがないドキュメント
]
$group の _id に存在しないフィールドを指定した場合や、フィールドの値が null のドキュメントは、デフォルトでは一つのグループとしてまとめられます(ここでは _id: null のグループとして表示)。
集計フレームワークは非常に多機能で、これ以外にも様々なステージや演算子があります。ここで紹介したのはほんの一例ですが、これらの基本を理解することで、より複雑な集計や分析へのステップとなります。
トランザクション (MongoDB 4.0以降) – 簡単な紹介
データベース操作において、複数の操作をまとめて一つの単位として扱い、全ての操作が成功するか、一つでも失敗したら全ての操作を取り消す(ロールバックする)仕組みを「トランザクション」と呼びます。これにより、データの一貫性を保つことができます。
MongoDBは、歴史的に単一ドキュメントに対する操作は常にアトミック(不可分)であることが保証されていました。つまり、一つのドキュメントの挿入、更新、削除は、完全に成功するか、全く何も起こらないかのどちらかであり、部分的に完了することはありません。
MongoDB 4.0以降では、レプリカセット環境において、複数のドキュメントやコレクションにまたがる操作をアトミックに実行できる「マルチドキュメントトランザクション」が導入されました。これにより、複雑な業務ロジックにおいてもデータの一貫性をより強固に保証できるようになりました。
トランザクションは、以下のコマンド(実際にはドライバ経由での使用が一般的)を使って開始、コミット(確定)、アボート(中止)を行います。
“`javascript
// mongosh での簡易的なトランザクション例
session = db.getMongo().startSession()
session.startTransaction()
try {
session.getDatabase(‘myNewDatabase’).collection(‘users’).insertOne({ name: “トランザクション ユーザー” })
session.getDatabase(‘myNewDatabase’).collection(‘orders’).insertOne({ userName: “トランザクション ユーザー”, item: “商品A” })
// 全て成功したらコミット
session.commitTransaction()
print(“Transaction committed.”)
} catch (error) {
// エラーが発生したらロールバック
session.abortTransaction()
print(“Transaction aborted: ” + error)
} finally {
session.endSession()
}
“`
これは、MongoDBを本格的にアプリケーションで利用する際に重要となる機能ですが、初心者向けの基本的なコマンド解説としては、このような機能があるということを知っておく程度で十分です。実際に利用する場合は、公式ドキュメントや各言語のMongoDBドライバのマニュアルを参照してください。トランザクションは、MongoDBが単なる「ドキュメントストア」ではなく、より高度なデータベース機能を提供していることの現れでもあります。
ユーザー管理とセキュリティ (入門)
MongoDBを本番環境で運用する場合、セキュリティは非常に重要です。特に、認証と認可(誰が、何に、どのような操作ができるか)の設定は必須です。ここでは、最も基本的なユーザー作成のコマンドを紹介します。
認証の有効化
デフォルトでは、MongoDBサーバーは認証なしで誰でも接続できてしまう状態(セキュリティ的には非常に危険)であることが多いです。本番環境では、設定ファイル (mongod.conf など) で認証を有効にする必要があります。
“`yaml
mongod.conf の設定例 (抜粋)
security:
authorization: enabled
“`
認証を有効にしたサーバーに接続する際は、ユーザー名とパスワードを指定して mongosh を起動する必要があります。
bash
mongosh --authenticationDatabase admin -u <username> -p
パスワードを入力するプロンプトが表示されます。
ユーザーの作成: db.createUser()
ユーザーを作成するには、通常、admin データベースに接続して createUser() メソッドを実行します。ユーザーには、どのデータベースに対してどのような権限を持つかを示す「ロール」を割り当てます。
“`javascript
use admin
db.createUser(
{
user: “
pwd: passwordPrompt(), // セキュアなパスワード入力プロンプトを使用
roles: [
{ role: “
// 複数のロールを指定可能
]
}
)
“`
<role_name> には、組み込みロール(例: read, readWrite, dbAdmin, userAdminAnyDatabase など)またはカスタムロールを指定します。
例:myNewDatabase に対して読み書き権限を持つユーザー appUser を作成する。
“`javascript
use admin
db.createUser(
{
user: “appUser”,
pwd: passwordPrompt(), // パスワード入力を求められる
roles: [
{ role: “readWrite”, db: “myNewDatabase” }
]
}
)
“`
注意点:
* passwordPrompt() を使うと、入力したパスワードが画面に表示されずに済みます。
* ユーザーを作成したら、認証を有効にしていない場合は有効にする必要があります。
* セキュリティ関連の設定は非常に重要であり、本番環境にデプロイする前に十分な理解と設定が必要です。公式ドキュメントのセキュリティに関する章を必ず参照してください。
まとめ
この記事では、MongoDBの初心者向けに、データベース、コレクション、そしてドキュメントに対する基本的な操作コマンドを詳細に解説しました。
- MongoDBとは: ドキュメント指向データベースであり、柔軟なスキーマと高い拡張性が特徴です。
- 接続:
mongoshを使ってMongoDBサーバーに接続しました。 - データベース/コレクション:
useでデータベースを選択し、show dbs,show collectionsで一覧を確認しました。 - ドキュメント操作 (CRUD):
- C (Create):
insertOne(),insertMany()でドキュメントを挿入しました。_idフィールドについて理解しました。 - R (Read):
find(),findOne()でドキュメントを検索しました。クエリドキュメント、比較演算子、論理演算子を使って様々な条件を指定する方法、limit(),skip(),sort(), プロジェクションを使って結果を整形・制限する方法を学びました。countDocuments(),estimatedDocumentCount()で件数を取得しました。 - U (Update):
updateOne(),updateMany()と$set,$inc,$unsetなどの更新オペレーターを使ってドキュメントを更新しました。 - D (Delete):
deleteOne(),deleteMany()でドキュメントを削除しました。drop(),dropDatabase()でコレクションやデータベース自体を削除しました。
- C (Create):
- インデックス:
createIndex(),getIndexes(),dropIndex()を使い、検索パフォーマンス向上のためのインデックス操作を学びました。explain()でクエリの実行計画を確認する方法も紹介しました。 - 集計 (Aggregation):
aggregate()メソッドと$match,$group,$project,$sort,$limit,$skipといった基本的なパイプラインステージを使った集計の考え方と例を学びました。 - その他: トランザクションと基本的なユーザー作成にも触れました。
これらの基本的なコマンドを習得すれば、MongoDBを使ったアプリケーション開発の第一歩を踏み出すことができます。
MongoDBは非常に奥が深く、この記事で解説した内容はごく一部です。次に学ぶべきトピックとしては、以下のようなものがあります。
- より高度なクエリ: 正規表現 (
$regex)、テキスト検索 ($text)、地理空間クエリなど。 - データモデリング: ドキュメントをどのように設計するか(埋め込み vs 参照)。
- 集計フレームワークの詳細: さらに多くのパイプラインステージや演算子。
- レプリカセット: データの冗長化と高可用性。
- シャーディング: 大規模データのための水平スケーリング。
- パフォーマンスチューニング: インデックス設計やクエリ最適化の深掘り。
- MongoDBドライバ: 各プログラミング言語からMongoDBを操作する方法。
ぜひ、公式ドキュメント(https://docs.mongodb.com/)などを参照しながら、さらにMongoDBの世界を深く探求してみてください。
この記事が、あなたのMongoDB学習の助けとなれば幸いです。頑張ってください!