jpskill.com
🛠️ 開発・MCP コミュニティ

mongodb

MongoDBのクエリ、集計、インデックス作成、管理など、データベース操作全般をサポートするSkill。

📜 元の英語説明(参考)

MongoDB queries, aggregation, indexing, and administration. Use when user mentions "mongodb", "mongo", "mongosh", "mongoose", "nosql", "document database", "mongodb atlas", "aggregation pipeline", "mongodb query", "collection", "mongodb index", "replica set", "mongodb backup", "mongodump", or working with MongoDB databases.

🇯🇵 日本人クリエイター向け解説

一言でいうと

MongoDBのクエリ、集計、インデックス作成、管理など、データベース操作全般をサポートするSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o mongodb.zip https://jpskill.com/download/6107.zip && unzip -o mongodb.zip && rm mongodb.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/6107.zip -OutFile "$d\mongodb.zip"; Expand-Archive "$d\mongodb.zip" -DestinationPath $d -Force; ri "$d\mongodb.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して mongodb.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → mongodb フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-17
取得日時
2026-05-17
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

MongoDB

mongosh の基本

# 接続
mongosh                                          # localhost:27017
mongosh "mongodb://localhost:27017/mydb"
mongosh "mongodb+srv://user:pass@cluster.mongodb.net/mydb"
mongosh --host rs0/host1:27017,host2:27017 --authenticationDatabase admin -u admin -p
show dbs                    // データベースを一覧表示
use mydb                    // データベースを切り替え (最初の書き込み時に作成)
show collections            // 現在の DB のコレクションを一覧表示
db.stats()                  // データベースの統計
db.collection.stats()       // コレクションの統計
db.getCollectionNames()     // プログラムによるコレクションの一覧表示
db.dropDatabase()           // 現在のデータベースを削除
db.createCollection("logs", { capped: true, size: 1048576, max: 1000 })

CRUD 操作

挿入 (Insert)

db.users.insertOne({ name: "Alice", email: "alice@example.com", age: 30 })
db.users.insertMany([
  { name: "Bob", email: "bob@example.com", age: 25 },
  { name: "Carol", email: "carol@example.com", age: 35 }
])
// ordered: false を指定した insertMany はエラーが発生しても続行します
db.users.insertMany(docs, { ordered: false })

検索 (Find)

db.users.find()                                    // すべてのドキュメント
db.users.find({ age: { $gt: 25 } })               // age > 25
db.users.findOne({ email: "alice@example.com" })   // 最初のマッチ
db.users.find({ status: "active" }, { name: 1, email: 1, _id: 0 })  // プロジェクション
db.users.find().sort({ age: -1 }).limit(10).skip(20)                 // ソート、ページネーション
db.users.countDocuments({ status: "active" })
db.users.distinct("status")

更新 (Update)

db.users.updateOne(
  { email: "alice@example.com" },
  { $set: { age: 31, updatedAt: new Date() } }
)
db.users.updateMany(
  { status: "inactive" },
  { $set: { archived: true }, $currentDate: { updatedAt: true } }
)
// Upsert: 見つからない場合は挿入
db.users.updateOne(
  { email: "dave@example.com" },
  { $set: { name: "Dave", age: 28 } },
  { upsert: true }
)
db.users.replaceOne(
  { _id: ObjectId("...") },
  { name: "Alice", email: "alice@new.com", age: 31 }
)

削除 (Delete)

db.users.deleteOne({ email: "bob@example.com" })
db.users.deleteMany({ status: "inactive", lastLogin: { $lt: ISODate("2024-01-01") } })
db.users.findOneAndDelete({ email: "bob@example.com" })  // 削除されたドキュメントを返します

クエリ演算子

比較と論理

{ age: { $eq: 30 } }                    // 等しい ( { age: 30 } と同じ)
{ age: { $gt: 25, $lte: 40 } }          // 範囲
{ status: { $in: ["active", "pending"] } }
{ status: { $nin: ["banned"] } }
{ $and: [{ age: { $gte: 18 } }, { status: "active" }] }
{ $or: [{ role: "admin" }, { age: { $gte: 21 } }] }
{ age: { $not: { $gt: 65 } } }

要素と評価

{ phone: { $exists: true } }             // フィールドが存在する
{ age: { $type: "number" } }             // BSON 型チェック
{ name: { $regex: /^alice/i } }          // 正規表現マッチ
{ bio: { $regex: "engineer", $options: "i" } }
{ score: { $mod: [10, 0] } }             // score が 10 で割り切れる

配列演算子

{ tags: { $all: ["mongodb", "nosql"] } }           // 配列がすべてを含む
{ tags: { $size: 3 } }                              // 配列の要素数がちょうど 3
{ results: { $elemMatch: { score: { $gt: 90 }, subject: "math" } } }
{ "scores.0": { $gt: 80 } }                         // 最初の要素 > 80

更新演算子

// フィールド演算子
{ $set: { status: "active" } }
{ $unset: { tempField: "" } }            // フィールドを削除
{ $inc: { views: 1, score: -5 } }       // 増減
{ $rename: { "old_field": "new_field" } }
{ $min: { lowScore: 50 } }              // 新しい値が低い場合に更新
{ $max: { highScore: 100 } }            // 新しい値が高い場合に更新
{ $mul: { price: 1.1 } }               // 1.1 を乗算

// 配列演算子
{ $push: { tags: "new-tag" } }
{ $push: { scores: { $each: [90, 85], $sort: -1, $slice: 10 } } }  // プッシュ、ソート、上位 10 件を保持
{ $addToSet: { tags: "unique-tag" } }    // 存在しない場合のみ追加
{ $pull: { tags: "old-tag" } }           // マッチする要素を削除
{ $pull: { results: { score: { $lt: 50 } } } }  // 条件で削除
{ $pop: { queue: -1 } }                 // 最初の要素を削除 (最後は 1)

アグリゲーションパイプライン

db.orders.aggregate([
  { $match: { status: "completed", createdAt: { $gte: ISODate("2025-01-01") } } },
  { $group: {
      _id: "$customerId",
      totalSpent: { $sum: "$amount" },
      orderCount: { $sum: 1 },
      avgOrder: { $avg: "$amount" },
      lastOrder: { $max: "$createdAt" }
  }},
  { $sort: { totalSpent: -1 } },
  { $limit: 10 },
  { $project: {
      customerId: "$_id",
      totalSpent: 1,
      orderCount: 1,
      avgOrder: { $round: ["$avgOrder", 2] },
      _id: 0
  }}
])

$lookup (結合)

db.orders.aggregate([
  { $lookup: {
      from: "users",
      localField: "customerId",
      foreignField: "_id",
      as: "customer"
  }},
  { $unwind: "$customer" },   // 単一要素配列をフラット化
  { $project: { amount: 1, "customer.name": 1, "customer.email": 1 } }
])

// パイプラインルックアップ (相関サブクエリ)
db.orders.aggregate([
  { $lookup: {
      from: "products",
      let: { productIds: "$items.productId" },
      pipeline: [
        { $match: { $expr: { $in: ["$_id", "$$productIds"] } } },
        { $project: { name: 1, price: 1 } }
      ],
      as: "productDetails"
  }}
])

$facet (1回のパスで複数のアグリゲーション)

db.products.aggregate([
  { $facet: {
      priceRanges: [
        { $bucket: { groupBy: "$price", boundaries: [0, 25, 50, 100, Infinity] } }
      ],
      topRated: [
        { $sort: { rating: -1 } },
        { $limit: 5 },
        { $project: { name: 1, rating: 1 } }
      ],
      totalCount: [
        { $count: "count" }
      ]
  }}
])

インデックス作成

// 単一フィールド
db.users.createIndex({ email: 1 })
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

MongoDB

mongosh Basics

# Connect
mongosh                                          # localhost:27017
mongosh "mongodb://localhost:27017/mydb"
mongosh "mongodb+srv://user:pass@cluster.mongodb.net/mydb"
mongosh --host rs0/host1:27017,host2:27017 --authenticationDatabase admin -u admin -p
show dbs                    // list databases
use mydb                    // switch database (creates on first write)
show collections            // list collections in current db
db.stats()                  // database stats
db.collection.stats()       // collection stats
db.getCollectionNames()     // programmatic collection list
db.dropDatabase()           // drop current database
db.createCollection("logs", { capped: true, size: 1048576, max: 1000 })

CRUD Operations

Insert

db.users.insertOne({ name: "Alice", email: "alice@example.com", age: 30 })
db.users.insertMany([
  { name: "Bob", email: "bob@example.com", age: 25 },
  { name: "Carol", email: "carol@example.com", age: 35 }
])
// insertMany with ordered: false continues on error
db.users.insertMany(docs, { ordered: false })

Find

db.users.find()                                    // all documents
db.users.find({ age: { $gt: 25 } })               // age > 25
db.users.findOne({ email: "alice@example.com" })   // first match
db.users.find({ status: "active" }, { name: 1, email: 1, _id: 0 })  // projection
db.users.find().sort({ age: -1 }).limit(10).skip(20)                 // sort, paginate
db.users.countDocuments({ status: "active" })
db.users.distinct("status")

Update

db.users.updateOne(
  { email: "alice@example.com" },
  { $set: { age: 31, updatedAt: new Date() } }
)
db.users.updateMany(
  { status: "inactive" },
  { $set: { archived: true }, $currentDate: { updatedAt: true } }
)
// Upsert: insert if not found
db.users.updateOne(
  { email: "dave@example.com" },
  { $set: { name: "Dave", age: 28 } },
  { upsert: true }
)
db.users.replaceOne(
  { _id: ObjectId("...") },
  { name: "Alice", email: "alice@new.com", age: 31 }
)

Delete

db.users.deleteOne({ email: "bob@example.com" })
db.users.deleteMany({ status: "inactive", lastLogin: { $lt: ISODate("2024-01-01") } })
db.users.findOneAndDelete({ email: "bob@example.com" })  // returns deleted doc

Query Operators

Comparison and Logical

{ age: { $eq: 30 } }                    // equals (same as { age: 30 })
{ age: { $gt: 25, $lte: 40 } }          // range
{ status: { $in: ["active", "pending"] } }
{ status: { $nin: ["banned"] } }
{ $and: [{ age: { $gte: 18 } }, { status: "active" }] }
{ $or: [{ role: "admin" }, { age: { $gte: 21 } }] }
{ age: { $not: { $gt: 65 } } }

Element and Evaluation

{ phone: { $exists: true } }             // field exists
{ age: { $type: "number" } }             // BSON type check
{ name: { $regex: /^alice/i } }          // regex match
{ bio: { $regex: "engineer", $options: "i" } }
{ score: { $mod: [10, 0] } }             // score divisible by 10

Array Operators

{ tags: { $all: ["mongodb", "nosql"] } }           // array contains all
{ tags: { $size: 3 } }                              // array has exactly 3 elements
{ results: { $elemMatch: { score: { $gt: 90 }, subject: "math" } } }
{ "scores.0": { $gt: 80 } }                         // first element > 80

Update Operators

// Field operators
{ $set: { status: "active" } }
{ $unset: { tempField: "" } }            // remove field
{ $inc: { views: 1, score: -5 } }       // increment/decrement
{ $rename: { "old_field": "new_field" } }
{ $min: { lowScore: 50 } }              // update if new value is lower
{ $max: { highScore: 100 } }            // update if new value is higher
{ $mul: { price: 1.1 } }               // multiply by 1.1

// Array operators
{ $push: { tags: "new-tag" } }
{ $push: { scores: { $each: [90, 85], $sort: -1, $slice: 10 } } }  // push, sort, keep top 10
{ $addToSet: { tags: "unique-tag" } }    // add only if not present
{ $pull: { tags: "old-tag" } }           // remove matching elements
{ $pull: { results: { score: { $lt: 50 } } } }  // remove by condition
{ $pop: { queue: -1 } }                 // remove first element (1 for last)

Aggregation Pipeline

db.orders.aggregate([
  { $match: { status: "completed", createdAt: { $gte: ISODate("2025-01-01") } } },
  { $group: {
      _id: "$customerId",
      totalSpent: { $sum: "$amount" },
      orderCount: { $sum: 1 },
      avgOrder: { $avg: "$amount" },
      lastOrder: { $max: "$createdAt" }
  }},
  { $sort: { totalSpent: -1 } },
  { $limit: 10 },
  { $project: {
      customerId: "$_id",
      totalSpent: 1,
      orderCount: 1,
      avgOrder: { $round: ["$avgOrder", 2] },
      _id: 0
  }}
])

$lookup (Join)

db.orders.aggregate([
  { $lookup: {
      from: "users",
      localField: "customerId",
      foreignField: "_id",
      as: "customer"
  }},
  { $unwind: "$customer" },   // flatten single-element array
  { $project: { amount: 1, "customer.name": 1, "customer.email": 1 } }
])

// Pipeline lookup (correlated subquery)
db.orders.aggregate([
  { $lookup: {
      from: "products",
      let: { productIds: "$items.productId" },
      pipeline: [
        { $match: { $expr: { $in: ["$_id", "$$productIds"] } } },
        { $project: { name: 1, price: 1 } }
      ],
      as: "productDetails"
  }}
])

$facet (Multiple Aggregations in One Pass)

db.products.aggregate([
  { $facet: {
      priceRanges: [
        { $bucket: { groupBy: "$price", boundaries: [0, 25, 50, 100, Infinity] } }
      ],
      topRated: [
        { $sort: { rating: -1 } },
        { $limit: 5 },
        { $project: { name: 1, rating: 1 } }
      ],
      totalCount: [
        { $count: "count" }
      ]
  }}
])

Indexing

// Single field
db.users.createIndex({ email: 1 })                    // ascending
db.users.createIndex({ email: 1 }, { unique: true })  // unique

// Compound (order matters: equality, sort, range)
db.orders.createIndex({ customerId: 1, createdAt: -1 })

// Multikey (automatically indexes array elements)
db.articles.createIndex({ tags: 1 })

// Text index (one per collection)
db.articles.createIndex({ title: "text", body: "text" })
db.articles.find({ $text: { $search: "mongodb aggregation" } })

// TTL (auto-delete documents after expiry)
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })

// Partial (index subset of documents)
db.orders.createIndex(
  { createdAt: -1 },
  { partialFilterExpression: { status: "active" } }
)

// Wildcard (index all fields or subfields in a document)
db.logs.createIndex({ "metadata.$**": 1 })

// List and manage indexes
db.users.getIndexes()
db.users.dropIndex("email_1")
db.users.dropIndexes()                                 // drops all non-_id indexes

Schema Design Patterns

Embedding vs Referencing

// Embedding: data accessed together, 1:few relationship
// Good for: addresses in user doc, comments on a blog post (bounded)
{
  _id: ObjectId("..."),
  name: "Alice",
  addresses: [
    { type: "home", street: "123 Main St", city: "Springfield" },
    { type: "work", street: "456 Corp Ave", city: "Shelbyville" }
  ]
}

// Referencing: data accessed independently, 1:many or many:many
// Good for: orders referencing products, users referencing groups
{
  _id: ObjectId("..."),
  customerId: ObjectId("..."),   // reference to users collection
  items: [
    { productId: ObjectId("..."), qty: 2, price: 29.99 }
  ]
}

Denormalization

Store computed or copied fields to avoid joins:

// Store author name directly on posts (update on author rename)
{ title: "My Post", authorId: ObjectId("..."), authorName: "Alice" }

Polymorphic Pattern

Single collection, different shapes distinguished by a type field:

// notifications collection
{ type: "email", to: "alice@example.com", subject: "Welcome", body: "..." }
{ type: "sms", to: "+1234567890", message: "Your code is 1234" }
{ type: "push", deviceToken: "abc...", title: "New message", payload: { ... } }

Mongoose ODM (Node.js)

Schema and Model

const mongoose = require("mongoose");
await mongoose.connect("mongodb://localhost:27017/mydb");

const userSchema = new mongoose.Schema({
  name: { type: String, required: true, trim: true },
  email: { type: String, required: true, unique: true, lowercase: true },
  age: { type: Number, min: 0 },
  role: { type: String, enum: ["user", "admin"], default: "user" },
  profile: {
    bio: String,
    avatar: String
  },
  tags: [String],
  createdAt: { type: Date, default: Date.now }
});

// Virtuals
userSchema.virtual("isAdmin").get(function () {
  return this.role === "admin";
});

// Instance methods
userSchema.methods.toPublic = function () {
  const { _id, name, email, role } = this.toObject();
  return { id: _id, name, email, role };
};

// Static methods
userSchema.statics.findByEmail = function (email) {
  return this.findOne({ email: email.toLowerCase() });
};

// Middleware (hooks)
userSchema.pre("save", function (next) {
  this.updatedAt = new Date();
  next();
});

const User = mongoose.model("User", userSchema);

Queries with Mongoose

const users = await User.find({ role: "admin" }).sort({ name: 1 }).limit(10).lean();
const user = await User.findById(id).select("name email");
await User.findOneAndUpdate({ email }, { $inc: { loginCount: 1 } }, { new: true });
await User.deleteMany({ lastLogin: { $lt: cutoffDate } });

Populate (Reference Resolution)

const postSchema = new mongoose.Schema({
  title: String,
  author: { type: mongoose.Schema.Types.ObjectId, ref: "User" }
});
const Post = mongoose.model("Post", postSchema);

const posts = await Post.find().populate("author", "name email").lean();
// Nested populate
const posts = await Post.find().populate({ path: "comments", populate: { path: "user" } });

lean()

lean() returns plain JS objects instead of Mongoose documents. Use for read-only queries -- skips hydration, significantly faster.

Transactions

const session = await mongoose.startSession();
session.startTransaction();
try {
  await Account.updateOne({ _id: from }, { $inc: { balance: -amount } }, { session });
  await Account.updateOne({ _id: to }, { $inc: { balance: amount } }, { session });
  await session.commitTransaction();
} catch (err) {
  await session.abortTransaction();
  throw err;
} finally {
  session.endSession();
}

Transactions require a replica set (or sharded cluster). For local dev, start mongod with --replSet rs0 and run rs.initiate().

MongoDB Atlas

Connection

# Connection string from Atlas dashboard
mongosh "mongodb+srv://cluster0.abc123.mongodb.net/mydb" --apiVersion 1 --username admin

# In application code
mongoose.connect("mongodb+srv://admin:password@cluster0.abc123.mongodb.net/mydb?retryWrites=true&w=majority")

Key Settings

  • Network Access: whitelist IP addresses or use 0.0.0.0/0 for dev (not production).
  • Database Access: create users with specific roles (readWrite, atlasAdmin).
  • Backups: Atlas provides continuous backups and point-in-time restore for M10+ clusters. Snapshots can be downloaded or restored to a new cluster.

Performance

explain()

db.orders.find({ customerId: ObjectId("...") }).explain("executionStats")

Key fields: totalDocsExamined vs nReturned (ratio should be close to 1:1), executionTimeMillis, winningPlan.stage (IXSCAN good, COLLSCAN bad), indexBounds.

Database Profiler

db.setProfilingLevel(1, { slowms: 100 })     // log queries slower than 100ms
db.system.profile.find().sort({ ts: -1 }).limit(5)
db.setProfilingLevel(0)                       // disable profiler

Index Hints

db.orders.find({ status: "active" }).hint({ status: 1, createdAt: -1 })
db.orders.find({ status: "active" }).hint("status_1_createdAt_-1")

Backup and Restore

# Full database dump
mongodump --uri="mongodb://localhost:27017/mydb" --out=/backup/$(date +%F)

# Specific collection
mongodump --uri="mongodb://localhost:27017/mydb" --collection=users --out=/backup

# Compressed dump
mongodump --uri="mongodb://localhost:27017/mydb" --gzip --archive=backup.gz

# Restore full database
mongorestore --uri="mongodb://localhost:27017" /backup/2025-04-13/

# Restore specific collection
mongorestore --uri="mongodb://localhost:27017/mydb" --collection=users /backup/mydb/users.bson

# Restore from compressed archive
mongorestore --uri="mongodb://localhost:27017" --gzip --archive=backup.gz

# Drop existing data before restoring
mongorestore --drop --uri="mongodb://localhost:27017" /backup/2025-04-13/

Replica Sets

Setup

# Start three mongod instances
mongod --replSet rs0 --port 27017 --dbpath /data/rs0-0
mongod --replSet rs0 --port 27018 --dbpath /data/rs0-1
mongod --replSet rs0 --port 27019 --dbpath /data/rs0-2
// Initiate from mongosh connected to one node
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27017" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
})
rs.status()
rs.conf()

Read Preference and Write Concern

// Read preference: where reads go
// primary (default), primaryPreferred, secondary, secondaryPreferred, nearest
db.users.find().readPref("secondaryPreferred")

// In connection string
"mongodb://host1,host2,host3/mydb?replicaSet=rs0&readPreference=secondaryPreferred"

// Write concern: how many nodes acknowledge a write
db.users.insertOne({ name: "Alice" }, { writeConcern: { w: "majority", wtimeout: 5000 } })

Change Streams

// Watch a collection for real-time changes
const changeStream = db.collection("orders").watch();
changeStream.on("change", (change) => {
  console.log(change.operationType, change.fullDocument);
});

// With filters
const pipeline = [{ $match: { "fullDocument.status": "shipped" } }];
const changeStream = db.collection("orders").watch(pipeline, { fullDocument: "updateLookup" });

// Resume after disconnect
const changeStream = db.collection("orders").watch([], { resumeAfter: lastResumeToken });

// Mongoose change streams
const stream = Order.watch();
stream.on("change", (data) => { /* handle */ });

Requires replica set or sharded cluster. Use fullDocument: "updateLookup" to include the full document on update events.

Common Patterns

Cursor-Based Pagination

// More efficient than skip/limit for large datasets
const pageSize = 20;
// First page
const firstPage = await db.orders.find().sort({ _id: -1 }).limit(pageSize).toArray();
// Next page: use last _id as cursor
const lastId = firstPage[firstPage.length - 1]._id;
const nextPage = await db.orders.find({ _id: { $lt: lastId } }).sort({ _id: -1 }).limit(pageSize).toArray();

Full-Text Search

db.articles.createIndex({ title: "text", body: "text" });
db.articles.find(
  { $text: { $search: "mongodb performance" } },
  { score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

// Atlas Search (more powerful, uses Lucene)
db.articles.aggregate([
  { $search: { index: "default", text: { query: "mongodb performance", path: ["title", "body"] } } },
  { $project: { title: 1, score: { $meta: "searchScore" } } }
])

Geospatial Queries

// Store GeoJSON point
db.places.insertOne({
  name: "Central Park",
  location: { type: "Point", coordinates: [-73.965, 40.782] }  // [lng, lat]
})
db.places.createIndex({ location: "2dsphere" })

// Find within radius (meters)
db.places.find({
  location: { $nearSphere: { $geometry: { type: "Point", coordinates: [-73.97, 40.77] }, $maxDistance: 2000 } }
})

// Find within polygon
db.places.find({
  location: { $geoWithin: { $geometry: { type: "Polygon", coordinates: [[[...], ...]] } } }
})