データベース
MongoDB
概要
MongoDBは、世界で最も人気のあるNoSQLドキュメントデータベースです。JSONライクなBSONドキュメント形式でデータを格納し、スケーラビリティ、パフォーマンス、柔軟性を重視して設計されています。動的スキーマとリッチクエリ言語により、現代のアプリケーション開発に最適化されています。
詳細
MongoDBは2007年に10gen(現MongoDB Inc.)によって開発されました。従来のリレーショナルデータベースの制約を解決するために、ドキュメント指向のアプローチを採用しています。JSONに似たBSON(Binary JSON)形式でデータを格納し、スキーマレスな設計により開発者の生産性向上を実現しています。
MongoDBの主な特徴:
- ドキュメント型データベース(BSON形式)
- 動的スキーマ
- 水平スケーリング(シャーディング)
- レプリケーション
- 豊富なクエリ言語
- インデックス機能
- 集約フレームワーク
- GridFS(大容量ファイル格納)
- 地理空間データサポート
- ACID特性(4.0以降でマルチドキュメントトランザクション)
メリット・デメリット
メリット
- 柔軟性: スキーマレス設計で迅速な開発が可能
- スケーラビリティ: 水平スケーリングに優れている
- パフォーマンス: 読み取り・書き込み処理が高速
- 開発者フレンドリー: JSONライクな直感的なデータ形式
- 豊富な機能: 全文検索、地理空間クエリ、時系列データ処理
- クラウド統合: MongoDB Atlasによるマネージドサービス
- コミュニティ: 活発なコミュニティとエコシステム
デメリット
- メモリ使用量: 大量のメモリを消費する場合がある
- JOINの制限: リレーショナルなJOIN操作が制限される
- データ一貫性: 結果的整合性を考慮する必要がある
- ストレージ使用量: BSONはJSONより多くのストレージを使用
- 学習コスト: NoSQLの概念とMongoDB特有の機能の習得が必要
主要リンク
書き方の例
インストール・セットアップ
# Ubuntu/Debian
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt update
sudo apt install mongodb-org
# macOS (Homebrew)
brew tap mongodb/brew
brew install mongodb-community
# Docker
docker run --name mongodb -p 27017:27017 -d mongo
# MongoDB起動
sudo systemctl start mongod
sudo systemctl enable mongod
# MongoShell接続
mongosh
基本操作(CRUD)
// データベース使用
use myapp
// コレクション作成とドキュメント挿入(Create)
db.users.insertOne({
name: "田中太郎",
email: "[email protected]",
age: 30,
address: {
city: "東京",
prefecture: "東京都"
},
hobbies: ["読書", "映画鑑賞"],
createdAt: new Date()
})
// 複数ドキュメント挿入
db.users.insertMany([
{
name: "佐藤花子",
email: "[email protected]",
age: 25,
address: { city: "大阪", prefecture: "大阪府" }
},
{
name: "山田次郎",
email: "[email protected]",
age: 35,
address: { city: "名古屋", prefecture: "愛知県" }
}
])
// ドキュメント読み取り(Read)
db.users.find()
db.users.findOne({ name: "田中太郎" })
db.users.find({ age: { $gte: 30 } })
db.users.find({ "address.city": "東京" })
// ドキュメント更新(Update)
db.users.updateOne(
{ name: "田中太郎" },
{ $set: { age: 31, email: "[email protected]" } }
)
db.users.updateMany(
{ age: { $lt: 30 } },
{ $set: { category: "young" } }
)
// ドキュメント削除(Delete)
db.users.deleteOne({ name: "田中太郎" })
db.users.deleteMany({ age: { $gt: 40 } })
データモデリング
// 埋め込みドキュメント
db.posts.insertOne({
title: "MongoDB入門",
content: "MongoDBはドキュメント型データベースです",
author: {
name: "田中太郎",
email: "[email protected]"
},
tags: ["mongodb", "nosql", "database"],
comments: [
{
author: "佐藤花子",
text: "とても参考になりました",
date: new Date()
}
],
createdAt: new Date()
})
// 参照(リレーション)
db.users.insertOne({
_id: ObjectId("65a1b2c3d4e5f6789abc1234"),
name: "田中太郎",
email: "[email protected]"
})
db.orders.insertOne({
userId: ObjectId("65a1b2c3d4e5f6789abc1234"),
items: [
{ product: "ノートPC", price: 80000 },
{ product: "マウス", price: 2000 }
],
total: 82000,
orderDate: new Date()
})
インデックス・最適化
// 単一フィールドインデックス
db.users.createIndex({ email: 1 })
// 複合インデックス
db.users.createIndex({ age: 1, "address.city": 1 })
// テキストインデックス(全文検索)
db.posts.createIndex({ title: "text", content: "text" })
// 地理空間インデックス
db.places.createIndex({ location: "2dsphere" })
// インデックス確認
db.users.getIndexes()
// 実行計画確認
db.users.explain().find({ email: "[email protected]" })
// 統計情報確認
db.users.stats()
実用例
// 集約フレームワーク
db.users.aggregate([
{ $match: { age: { $gte: 25 } } },
{ $group: {
_id: "$address.prefecture",
count: { $sum: 1 },
avgAge: { $avg: "$age" }
}},
{ $sort: { count: -1 } }
])
// 全文検索
db.posts.find({ $text: { $search: "MongoDB NoSQL" } })
// 地理空間クエリ
db.places.find({
location: {
$near: {
$geometry: { type: "Point", coordinates: [139.6917, 35.6895] },
$maxDistance: 1000
}
}
})
// 時系列データクエリ
db.logs.find({
timestamp: {
$gte: ISODate("2024-01-01T00:00:00Z"),
$lt: ISODate("2024-02-01T00:00:00Z")
}
})
ベストプラクティス
// トランザクション(レプリカセット必要)
const session = db.getMongo().startSession()
session.startTransaction()
try {
db.accounts.updateOne(
{ _id: "account1" },
{ $inc: { balance: -100 } },
{ session }
)
db.accounts.updateOne(
{ _id: "account2" },
{ $inc: { balance: 100 } },
{ session }
)
session.commitTransaction()
} catch (error) {
session.abortTransaction()
throw error
} finally {
session.endSession()
}
// バルク操作
const bulk = db.users.initializeUnorderedBulkOp()
bulk.insert({ name: "User1", email: "[email protected]" })
bulk.find({ name: "User2" }).update({ $set: { active: true } })
bulk.find({ name: "User3" }).remove()
bulk.execute()
// データベース設定
// mongod.conf
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
net:
port: 27017
bindIp: 127.0.0.1
replication:
replSetName: "rs0"
Node.js での使用例
const { MongoClient } = require('mongodb')
// 接続
const client = new MongoClient('mongodb://localhost:27017')
async function main() {
try {
await client.connect()
const db = client.db('myapp')
const collection = db.collection('users')
// データ挿入
await collection.insertOne({
name: '田中太郎',
email: '[email protected]',
age: 30
})
// データ検索
const users = await collection.find({ age: { $gte: 25 } }).toArray()
console.log(users)
} finally {
await client.close()
}
}
main().catch(console.error)