こんにちは、かつコーチです。
前回はCRUD操作の基本を解説し、find({ status: "active" })のような単純な一致条件での検索まで扱いました。
今回は一歩進んで、SQLの>やIN、LIKEに相当するクエリ演算子の使い方を解説します。
MongoDBの検索条件は、$から始まるキーワードを使ってオブジェクトの形で表現するのが特徴です。
SQLの演算子と1つずつ対応させながら覚えていきましょう。
比較演算子:gt・lt・gte・lte・$ne
数値の範囲検索
SQLでWHERE age > 20のように書く比較条件は、MongoDBでは$gt(greater than)などの演算子を使います。
| SQL | MongoDBクエリ演算子 | 意味 |
|---|---|---|
> | $gt | より大きい |
>= | $gte | 以上 |
< | $lt | より小さい |
<= | $lte | 以下 |
!= | $ne | 等しくない |
// age が 20 より大きいユーザーを検索
// SQLの WHERE age > 20 に相当
db.users.find({ age: { $gt: 20 } })
// age が 20以上30以下のユーザーを検索
// SQLの WHERE age BETWEEN 20 AND 30 に相当
db.users.find({ age: { $gte: 20, $lte: 30 } })
同じフィールドに対して複数の演算子を1つのオブジェクトにまとめて書けるのがポイントです。$gteと$lteを組み合わせることで、SQLのBETWEENと同じ範囲検索が表現できます。
配列に関する演算子:in・nin
INに相当する$in
SQLのWHERE status IN ('active', 'pending')に相当するのが$inです。
複数の候補のいずれかに一致するドキュメントを検索します。
// status が active または pending のユーザーを検索
// SQLの WHERE status IN ('active', 'pending') に相当
db.users.find({ status: { $in: ["active", "pending"] } })
// $nin は $in の否定版。SQLの NOT IN に相当
db.users.find({ status: { $nin: ["deleted", "banned"] } })
配列フィールドに対する検索
MongoDBならではの使い方として、フィールド自体が配列の場合の検索があります。
SQLでは配列型のカラムを扱うのが一般的ではないため、ここは新しい感覚が必要です。
// tags 配列に "VIP" を含むドキュメントを検索
db.users.find({ tags: "VIP" })
// tags 配列に "VIP" と "新規" の両方を含むドキュメントを検索
db.users.find({ tags: { $all: ["VIP", "新規"] } })
配列フィールドに対して単純に値を書くだけで「配列内にその値が含まれるか」を検索できる点は、SQLにはないMongoDB特有の便利さです。
パターンマッチ:$regex
LIKEに相当する正規表現検索
SQLのWHERE name LIKE '%田中%'に相当するのが$regexです。
MongoDBでは、SQLのLIKEよりも表現力の高い正規表現をそのまま条件に使えます。
// name に "田中" を含むユーザーを検索
// SQLの WHERE name LIKE '%田中%' に相当
db.users.find({ name: { $regex: "田中" } })
// 大文字・小文字を区別せず "tanaka" を含むメールアドレスを検索
db.users.find({ email: { $regex: "tanaka", $options: "i" } })
// 前方一致検索(SQLの LIKE '田中%' に相当)
db.users.find({ name: { $regex: "^田中" } })
$options: "i"を付けると、大文字・小文字を区別しない検索になります。
SQLのLIKEは基本的にワイルドカード(%や_)しか使えませんが、$regexは正規表現のフル機能が使えるため、より複雑なパターンマッチが可能です。
❌よくある失敗:$regexの多用によるパフォーマンス劣化
私が実務で経験した失敗として、$regexを使った前方一致検索ではなく、部分一致検索({ $regex: "田中" }のように先頭に^を付けない書き方)を大量データに対して多用してしまい、検索が極端に遅くなったことがあります。
❌ Before:部分一致検索はインデックスを活用できず、全件スキャンになりやすい
db.users.find({ name: { $regex: "田中" } })
// データ件数が多いとレスポンスが数秒かかることも
✅ After:前方一致(^始まり)ならインデックスを活用できる
db.users.find({ name: { $regex: "^田中" } })
// nameフィールドにインデックスがあれば、範囲スキャンとして高速化される
インデックスについてはMG07で詳しく扱いますが、「部分一致検索は原則インデックスが効かない」というのはSQLのLIKE '%...%'と同じ制約です。
検索頻度の高いフィールドで自由な部分一致検索が必要な場合は、専用の全文検索エンジン(Atlas SearchやElasticsearch)の導入を検討するのが定石です。
論理演算子:and・or・$not
複数条件の組み合わせ
複数の条件をAND・ORで組み合わせたい場合は、$and・$orを使います。
// age が 20以上 かつ status が active
// 実は複数条件を並べるだけで暗黙的にANDになるため、$andは省略可能なことが多い
db.users.find({ age: { $gte: 20 }, status: "active" })
// age が 20未満 または status が inactive
// SQLの WHERE age < 20 OR status = 'inactive' に相当
db.users.find({
$or: [
{ age: { $lt: 20 } },
{ status: "inactive" }
]
})
複数の条件フィールドを並べるだけで暗黙のANDになる点は、初心者がつまずきやすいポイントです。
ORで組み合わせたい場合のみ、明示的に$orを使う必要があると覚えておきましょう。
まとめ
この記事のポイント
- 比較演算子(
$gt・$gte・$lt・$lte・$ne)は、SQLの>やBETWEENに相当する $in・$ninはSQLのIN・NOT INに相当し、配列フィールドの部分一致検索にも使える$regexはSQLのLIKEよりも表現力が高いが、部分一致検索は原則インデックスが効かない- 複数条件を並べると暗黙的にANDになる。ORにしたい場合は
$orを明示する
次に読むべき記事
検索条件の書き方が身についたところで、次回はさらに一歩進んだ「集約パイプライン(Aggregation)の基本」で、SQLのGROUP BYに相当する集計処理を解説します。
タグ: MongoDB 中級者向け 基本操作