MongoDB: ドキュメント削除とNode.js入門

最終更新:2026-08-26

ドキュメント削除はデータクリーンアップの核心操作です。本コースではNode.jsとMongooseの実践も紹介します。

deleteOne/deleteManyのマスター、Node.jsとMongooseの連携、スキーマ定義、モデルCRUD操作を学びます。

1. 学習内容



2. フルスタックエンジニアの実話

(1) 課題:期限切れデータのクリーンアップに複雑なスクリプトが必要

Bobはeコマースプラットフォームで期限切れの注文と無効化されたユーザーアカウントを定期的にクリーンアップする必要があります:

JAVASCRIPT
// ❌ 反例:複数回検索してから削除(遅い + 競合状態)
const expiredOrders = await Order.find({ expiryDate: { $lt: new Date() } });
for (const order of expiredOrders) {
  await Order.deleteOne({ _id: order._id });
}
// N回のネットワーク往復、N秒の削除操作

(2) MongoDB + Mongooseでの一括削除による解決策

JAVASCRIPT
// ✅ 正例:一括削除
const result = await Order.deleteMany({
  expiryDate: { $lt: new Date() }
});
// 1回の操作で全ての期限切れ注文を削除

// Mongooseスキーマ定義
const OrderSchema = new mongoose.Schema({
  userId: { type: mongoose.Schema.Types.ObjectId, required: true },
  item: [{ sku: String, qty: Number, price: mongoose.Schema.Types.Decimal128 }],
  total: { type: mongoose.Schema.Types.Decimal128, required: true },
  status: { type: String, enum: ['pending', 'paid', 'shipped', 'delivered'], default: 'pending' },
  expiryDate: Date,
  createdAt: { type: Date, default: Date.now }
}, { timestamps: true });

const Order = mongoose.model('Order', OrderSchema);

100%
graph LR
    A[削除操作] --> B[deleteOne<br/>単一削除]
    A --> C[deleteMany<br/>一括削除]
    A --> D[findOneAndDelete<br/>原子的返却]
    A --> E[drop<br/>コレクション削除]
    A --> F[dropDatabase<br/>データベース削除]

    style D fill:#d4edda

3. deleteOne:単一ドキュメントを削除

概念説明明: deleteOneはフィルター条件に一致する最初のドキュメントを削除します。MongoDBで最も基本的な削除メソッドです。削除は取り消し不可能です。「ゴミ箱」のような仕組みはなく、削除されたドキュメントを直接復元することはできません(バックアップまたはoplogがない限り)。そのため、本番環境での削除操作は極めて慎重に行う必要があります。

仕組み: deleteOneの実行フローは以下の通りです:マッチングフェーズ(フィルターに基づいて最初のドキュメントを特定)→ 削除フェーズ(コレクションからドキュメントを削除)→ インデックス更新(関連するインデックスエントリを削除)→ 書き込み確認。操作全体が単一ドキュメントに対して原子的です。削除後、ディスクスペースは即座に解放されず、再利用可能なスペースとしてマークされます。

100%
sequenceDiagram
    participant App as アプリケーション
    participant Mongo as MongoDB
    participant WT as WiredTiger

    App->>Mongo: deleteOne({ sku: "PHONE-001" })
    Mongo->>Mongo: フィルターをマッチ(インデックススキャン)
    Mongo->>WT: ドキュメントを削除 + インデックスを更新
    WT-->>Mongo: 削除を確認
    Mongo-->>App: { acknowledged: true, deletedCount: 1 }
パラメータ 説明
filter ドキュメント 検索条件(必須)
options ドキュメント writeConcernなど(任意)
戻り値フィールド 説明
acknowledged Boolean 書き込みが確認されたかどうか
deletedCount Number 削除されたドキュメント数(0または1)
JAVASCRIPT
// === deleteOne基本使用法 ===
db.products.deleteOne({ sku: 'PHONE-001' });

出力:

TEXT 📖 参照専用
{ acknowledged: true, deletedCount: 1 }
戻り値フィールド 意味
acknowledged 確認されたかどうか
deletedCount 削除されたドキュメント数(0または1)

▶ サンプル 1:deleteOneの実践

JAVASCRIPT
// === 指定_idのドキュメントを削除 ===
db.users.deleteOne({ _id: ObjectId('507f1f77bcf86cd799439011') });

// === 指定条件に基づいて削除(最初のマッチ)===
db.logs.deleteOne({ level: 'debug' });

// === Mongoose相当の記述 ===
const result = await Product.deleteOne({ sku: 'PHONE-001' });
console.log(result.deletedCount);  // 1

出力:

TEXT 📖 参照専用
1


4. deleteMany:一括削除

概念説明明: deleteManyはフィルター条件に一致する全ドキュメントを削除します。データの一括クリーンアップにおける主要メソッドです。最初のマッチのみを削除するdeleteOneとは異なり、deleteManyは一度に数万件のドキュメントを削除できます。典型的な使用例:期限切れログのクリーンアップ、無効化されたユーザーデータの削除、テストデータの削除など。

仕組み: deleteManyはまず全マッチドキュメントを取得し、その後1件ずつ削除します。削除プロセスはトランザクションではありません。途中で失敗した場合、既に削除されたドキュメントは復元されません。一括削除を行う際は、バッチ単位での実行を検討し、コレクションが長時間ロックされるのを避けてください。

観点 deleteOne deleteMany
マッチ範囲 最初の1件 全マッチ
削除件数 0または1 0からN
用途 単一削除 一括クリーンアップ
リスク 低い 中程度(操作ミスの影響が大きい)
JAVASCRIPT
// === deleteMany基本使用法 ===
db.products.deleteMany({ category: 'Discontinued' });

// === 全ての期限切れ注文を削除 ===
db.orders.deleteMany({
  expiryDate: { $lt: new Date() }
});

// === 特定条件を満たす複数ドキュメントを削除 ===
db.logs.deleteMany({
  level: { $in: ['debug', 'info'] },
  createdAt: { $lt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) }
});

▶ サンプル 2:deleteManyの実践

JAVASCRIPT
// === 30日前のエントリをクリーンアップ ===
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
const result = await Log.deleteMany({ createdAt: { $lt: thirtyDaysAgo } });
console.log(`Deleted ${result.deletedCount} old logs`);

出力:

TEXT 📖 参照専用
Deleted 1523 old logs
JAVASCRIPT
// === ログアウトしたユーザーのセッションを削除 ===
await Session.deleteMany({ userId: deletedUserId });

// === コレクション内の全ドキュメントを削除(注意して使用!)===
db.products.deleteMany({});
// ⚠️ これによりproductsコレクション内の全ドキュメントが削除されます


5. findOneAndDelete 原子的返却

概念説明明: findOneAndDeleteは特別な削除メソッドで、ドキュメントを削除すると同時に削除されたドキュメントの内容を返却します。これは「先に検索してから削除」の競合状態を解決します。従来のアプローチでは、まずfindOneでドキュメントを取得してからdeleteOneで削除する必要がありました。この間にドキュメントが他の操作によって変更または削除される可能性があります。findOneAndDeleteは検索と削除を単一の原子的操作に結合します。

仕組み: findOneAndDeleteはドキュメントレベルで原子的操作を実行します:マッチするドキュメントを特定 → ドキュメントの内容を記録 → ドキュメントを削除 → 記録した内容を返却。デフォルトでは削除前のドキュメントの状態を返却します。projectionオプションを使用してどのフィールドを返却するかを制御できます。

100%
graph TB
    A[ドキュメントを削除して取得する必要がある] --> B{方法の選択}
    B --> C[❌ 先に確認してから削除<br/>findOne + deleteOne<br/>競合状態のリスク]
    B --> D[✅ findOneAndDelete<br/>原子的操作<br/>競合のリスクなし]
    B --> E[✅ findOneAndDelete + sort<br/>原子的操作 + 順序<br/>FIFOキュー]

    style D fill:#d4edda
    style E fill:#d4edda
利点 説明
原子性 検索と削除が単一の操作で実行され、競合状態を回避
ドキュメント返却 削除されたドキュメントを直接取得、2回目の検索が不要
ソート対応 sortオプションと併用で順序付き消費が可能
用途 キュータスク、メッセージ消費、在庫引当
JAVASCRIPT
// === findOneAndDelete原子的操作 ===
const deletedDoc = db.products.findOneAndDelete({ sku: 'PHONE-001' });

出力:

TEXT 📖 参照専用
{ _id: ..., sku: 'PHONE-001', title: 'Phone', price: 599, ... }
JAVASCRIPT
// 削除されたドキュメントを復元(デフォルトは削除前の状態)
console.log(deletedDoc);

出力:

TEXT 📖 参照専用
{ _id: ObjectId('...'), sku: 'PHONE-001', title: 'Smartphone X', price: NumberDecimal('599.99'), ... }
JAVASCRIPT
// === 存在しない場合はnullを返却 ===
const result = db.products.findOneAndDelete({ sku: 'NOT_EXIST' });
console.log(result);  // null

出力:

TEXT 📖 参照専用
null
利点 説明
原子性 検索と削除が単一の操作で実行され、競合状態を回避
ドキュメント返却 削除されたドキュメントを直接取得、2回目の検索が不要
用途 キュータスク、メッセージ消費、在庫引当

▶ サンプル 3:findOneAndDeleteの実践

JAVASCRIPT
// === シーン:メッセージキュー(FIFO)===
const message = await Queue.findOneAndDelete(
  { status: 'pending' },
  { sort: { createdAt: 1 } }  // 最も古いものから消費
);

// === シーン:タスクを請求 ===
const task = await Task.findOneAndDelete({
  status: 'available',
  assignee: null
});
if (task) {
  console.log(`Claimed task: ${task._id}`);
}

// === Mongoose相当の記述 ===
const message = await Queue.findOneAndDelete(
  { status: 'pending' },
  { sort: { createdAt: 1 } }
);


6. drop コレクションとdropDatabase

概念説明明: dropdropDatabaseは最も徹底的な削除操作です。dropはコレクション全体(全ドキュメントとインデックスを含む)を削除し、dropDatabaseはデータベース全体(全コレクションを含む)を削除します。deleteMany({})とは異なり、drop操作はデータを削除するだけでなく、コレクションのメタデータ(インデックス定義、スキーマ検証ルール、capped設定など)も削除します。

比較分析:

観点 deleteMany({}) drop() dropDatabase()
削除範囲 コレクション内の全ドキュメント コレクション全体 データベース全体
インデックス保持 ✅ 保持 ❌ 全削除 ❌ 全削除
capped設定保持 ✅ 保持 ❌ 削除 ❌ 削除
スキーマ検証保持 ✅ 保持 ❌ 削除 ❌ 削除
速度 低速(1件ずつ削除) 高速(即座にスペース解放) 高速
復元可能性 oplogで復元可能 復元極めて困難 復元極めて困難
JAVASCRIPT
// === コレクション削除 ===
db.products.drop();

出力:

TEXT 📖 参照専用
true
JAVASCRIPT
// === データベース削除 ===
db.dropDatabase();

出力:

TEXT 📖 参照専用
{ "dropped" : "shopdb", "ok" : 1 }
JAVASCRIPT
// === 注意して使用:コレクション内の全データを削除するがコレクション自体は保持 ===
db.products.deleteMany({});
// 同等だがコレクション構造を保持(インデックス、capped設定)

▶ サンプル 4:dropdeleteManyの使い分け

JAVASCRIPT
// シーン:一時テストコレクションのクリーンアップ
// ✅ 推奨:drop(コレクション+インデックスを削除、クリーン)
db.test_results.drop();

// ✅ コレクション構造を保持:deleteMany(ドキュメントのみクリア)
db.user_sessions.deleteMany({});


7. Node.js + Mongoose:MongoDBへの接続

概念概要: MongooseはNode.jsエコシステムで最も人気のあるMongoDB ODM(Object Document Modeling)で、スキーマ定義、データ検証、ミドルウェア、結合検索などの高度な機能を提供します。本節ではMongoDBへの接続から始め、Mongooseの核心概念を段階的に紹介します。

仕組み: MongooseがMongoDBに接続するプロセスは以下のステップで構成されます:接続インスタンスの作成 → TCP接続の確立 → 認証(必要な場合)→ データベースの選択 → 接続プールの初期化 → connectedイベントのトリガー。デフォルトでMongooseは接続プール(通常5〜100接続)を維持し、TCP接続を頻繁に確立・切断することを避けます。

100%
sequenceDiagram
    participant App as Node.jsアプリケーション
    participant Mongoose as mongoose
    participant Mongo as MongoDB

    App->>Mongoose: mongoose.connect(uri)
    Mongoose->>Mongo: TCP接続を確立
    Mongo-->>Mongoose: 接続確認
    Mongoose->>Mongo: 認証(必要な場合)
    Mongo-->>Mongoose: 認証成功
    Mongoose->>Mongoose: 接続プールを初期化
    Mongoose-->>App: 'connected'イベントをトリガー
    Note over App,Mongoose: 接続準備完了、CRUD実行可能
接続方法 URI形式 用途
ローカル単独 mongodb://localhost:27017/shopdb 開発・テスト
認証付き mongodb://user:pass@host:27017/db 本番環境
レプリカセット mongodb://host1,host2,host3/db?replicaSet=rs0 高可用性
SRV接続 mongodb+srv://user:pass@cluster/db MongoDB Atlas

(1) インストールと接続

BASH
# === インストール ===
npm install mongoose
JAVASCRIPT
// === 基本接続 ===
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/shopdb')
  .then(() => console.log('Connected to MongoDB'))
  .catch(err => console.error('Connection error:', err));

(2) 接続イベントの処理

JAVASCRIPT
// === 接続イベント監視 ===
const mongoose = require('mongoose');

mongoose.connection.on('connected', () => {
  console.log('Mongoose connected to MongoDB');
});

mongoose.connection.on('error', (err) => {
  console.error('Mongoose connection error:', err);
});

mongoose.connection.on('disconnected', () => {
  console.log('Mongoose disconnected');
});

// === アプリケーション終了時に接続を閉じる ===
process.on('SIGINT', async () => {
  await mongoose.connection.close();
  console.log('Mongoose connection closed through app termination');
  process.exit(0);
});

(3) 接続オプション

JAVASCRIPT
// === 本番環境の接続オプション ===
mongoose.connect('mongodb://localhost:27017/shopdb', {
  maxPoolSize: 50,         // 接続プールサイズ
  minPoolSize: 5,
  connectTimeoutMS: 10000, // 接続タイムアウト
  socketTimeoutMS: 45000,  // ソケットタイムアウト
  serverSelectionTimeoutMS: 5000,
  heartbeatFrequencyMS: 10000
});


8. Mongooseスキーマとモデル

概念説明明: スキーマはMongooseの核心概念で、ドキュメントの構造、フィールド型、デフォルト値、検証ルール、インデックスなどを定義します。モデルはスキーマから作成され、データベース操作のためのインターフェースを提供します(findcreateupdateOnedeleteOneなど)。スキーマは「設計図」、モデルは「工場」です。

仕組み: Mongooseはスキーマ定義を内部でMongoDBのドキュメント構造に変換します。type: StringはBSONの文字列型に、required: trueは挿入時の検証ルールに、default: Date.nowはサーバー側のデフォルト値生成に変換されます。モデルのCRUDメソッドを呼び出すと、Mongooseはまずスキーマ検証を実行し、その後MongoDBネイティブドライバのメソッドに変換してサーバーに送信します。

100%
graph TB
    A[Schema スキーマ定義] --> B[Model モデル作成]
    B --> C[Document ドキュメントインスタンス]
    
    A --> A1[フィールド型<br/>String/Number/Date/ObjectId]
    A --> A2[検証ルール<br/>required/enum/min/max]
    A --> A3[デフォルト値<br/>default]
    A --> A4[インデックス<br/>index/unique]
    
    B --> B1[CRUDメソッド<br/>find/create/update/delete]
    C --> C1[インスタンスメソッド<br/>save/remove]

    style A fill:#cce5ff
    style B fill:#d4edda

(1) スキーマ定義

JAVASCRIPT
// === 基本スキーマ ===
const mongoose = require('mongoose');
const { Schema } = mongoose;

const productSchema = new Schema({
  sku: { type: String, required: true, unique: true },
  title: { type: String, required: true },
  description: { type: String, maxlength: 500 },
  price: { type: mongoose.Schema.Types.Decimal128, required: true, min: 0 },
  category: { type: String, enum: ['Electronics', 'Books', 'Clothing'] },
  stock: { type: Number, default: 0, min: 0 },
  isActive: { type: Boolean, default: true },
  tags: [{ type: String }],
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now }
}, {
  timestamps: true,       // createdAt/updatedAtを自動管理
  versionKey: '__v',      // バージョンキー
  collection: 'products'  // コレクション名
});

// === モデル作成 ===
const Product = mongoose.model('Product', productSchema);

(2) スキーマの型

JAVASCRIPT
// === サポートされる型 ===
const exampleSchema = new Schema({
  string: String,
  number: Number,
  date: Date,
  buffer: Buffer,
  boolean: Boolean,
  objectId: mongoose.Schema.Types.ObjectId,
  decimal: mongoose.Schema.Types.Decimal128,
  array: [String],
  nested: {
    field1: String,
    field2: Number
  }
});

(3) 検証とインデックス

JAVASCRIPT
// === 検証ルール ===
const userSchema = new Schema({
  email: {
    type: String,
    required: [true, 'Email is required'],
    unique: true,
    lowercase: true,
    trim: true,
    match: [/^\S+@\S+\.\S+$/, 'Please use a valid email address']
  },
  age: {
    type: Number,
    min: [0, 'Age must be positive'],
    max: 120
  },
  role: {
    type: String,
    enum: {
      values: ['user', 'admin', 'guest'],
      message: '{VALUE} is not a valid role'
    }
  }
});

// === インデックス ===
userSchema.index({ email: 1 }, { unique: true });
userSchema.index({ createdAt: -1 });

▶ サンプル 5:完全なスキーマ定義

JAVASCRIPT
const mongoose = require('mongoose');
const { Schema } = mongoose;

const orderSchema = new Schema({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  items: [{
    sku: { type: String, required: true },
    productName: { type: String, required: true },
    qty: { type: Number, required: true, min: 1 },
    price: { type: mongoose.Schema.Types.Decimal128, required: true }
  }],
  total: {
    type: mongoose.Schema.Types.Decimal128,
    required: true,
    min: 0
  },
  status: {
    type: String,
    enum: ['pending', 'paid', 'shipped', 'delivered', 'cancelled'],
    default: 'pending'
  },
  shippingAddress: {
    street: String,
    city: String,
    state: String,
    zip: String,
    country: { type: String, default: 'Japan' }
  },
  notes: { type: String, maxlength: 500 }
}, {
  timestamps: true,
  toJSON: { virtuals: true },
  toObject: { virtuals: true }
});

// バーチャルフィールド
orderSchema.virtual('itemCount').get(function() {
  return this.items.reduce((sum, item) => sum + item.qty, 0);
});

// ミドルウェア
orderSchema.pre('save', function(next) {
  if (this.isModified('status') && this.status === 'delivered') {
    this.deliveredAt = new Date();
  }
  next();
});

const Order = mongoose.model('Order', orderSchema);


9. Mongoose CRUD操作

概念説明明: MongooseのCRUDメソッドはMongoDBネイティブドライバよりも高レベルな抽象化を提供します。save()メソッドはスキーマ検証、ミドルウェア、デフォルト値の生成を自動的に処理します。find()メソッドは結果をMongooseドキュメントオブジェクトに変換し、インスタンスメソッドやバーチャルフィールドへのアクセスを可能にします。

仕組み: MongooseのCRUDメソッドは実際にはMongoDBネイティブドライバを内部的に呼び出していますが、追加のロジックが挟まれています:1) スキーマ検証(設定で無効化可能)、2) ミドルウェア(pre/postフック)、3) 型変換(Decimal128など)、4) キャスト(文字列をObjectIdに自動変換など)、5) ドキュメントハイドレート(プレーンオブジェクトをMongooseドキュメントに変換)。lean()を使用するとハイドレート処理をスキップでき、パフォーマンスが3〜5倍向上します。

(1) 作成

JAVASCRIPT
// === 新規ドキュメント作成 ===
const product = new Product({
  sku: 'PHONE-001',
  title: 'Smartphone X',
  price: mongoose.Types.Decimal128.fromString('599.99'),
  category: 'Electronics'
});

await product.save();

// === create()メソッド ===
const product = await Product.create({
  sku: 'PHONE-002',
  title: 'Smartphone Y',
  price: mongoose.Types.Decimal128.fromString('499.99')
});

// === 一括作成 ===
const products = await Product.insertMany([
  { sku: 'PHONE-003', title: 'Phone A', price: 299.99 },
  { sku: 'PHONE-004', title: 'Phone B', price: 399.99 }
]);

(2) 読み取り

JAVASCRIPT
// === 全ドキュメント検索 ===
const products = await Product.find();

// === 条件付き検索 ===
const electronics = await Product.find({ category: 'Electronics' });

// === 単一ドキュメント検索 ===
const product = await Product.findOne({ sku: 'PHONE-001' });

// === IDで検索 ===
const product = await Product.findById('507f1f77bcf86cd799439011');

// === プロジェクション + ソート + ページネーション ===
const products = await Product.find({ category: 'Electronics' })
  .select('sku title price')
  .sort({ price: -1 })
  .skip(0)
  .limit(20)
  .lean();  // パフォーマンス最適化

(3) 更新

JAVASCRIPT
// === updateOne ===
const result = await Product.updateOne(
  { sku: 'PHONE-001' },
  { $set: { price: mongoose.Types.Decimal128.fromString('549.99') } }
);

// === findByIdAndUpdate ===
const product = await Product.findByIdAndUpdate(
  '507f1f77bcf86cd799439011',
  { $inc: { stock: -1 } },
  { new: true }  // 更新後のドキュメントを返却
);

// === ドキュメントsave()で更新 ===
const product = await Product.findOne({ sku: 'PHONE-001' });
product.price = mongoose.Types.Decimal128.fromString('499.99');
product.lastUpdated = new Date();
await product.save();

(4) 削除

JAVASCRIPT
// === deleteOne ===
const result = await Product.deleteOne({ sku: 'PHONE-001' });

// === deleteMany ===
const result = await Product.deleteMany({ category: 'Discontinued' });

// === findByIdAndDelete ===
const product = await Product.findByIdAndDelete('507f1f77bcf86cd799439011');

// === ドキュメントremove()で削除 ===
const product = await Product.findOne({ sku: 'PHONE-001' });
await product.remove();

▶ サンプル 6:Mongoose CRUD実践

JAVASCRIPT
// === シーン:eコマース注文処理 ===
async function createOrder(userId, items) {
  const session = await mongoose.startSession();
  session.startTransaction();

  try {
    // 1. 在庫チェック
    for (const item of items) {
      const product = await Product.findOne({ sku: item.sku }).session(session);
      if (!product || product.stock < item.qty) {
        throw new Error(`Insufficient stock for ${item.sku}`);
      }
    }

    // 2. 注文作成
    const order = await Order.create([{
      userId,
      items: items.map(item => ({
        sku: item.sku,
        productName: item.productName,
        qty: item.qty,
        price: item.price
      })),
      total: items.reduce((sum, item) => sum + item.qty * item.price, 0),
      status: 'pending'
    }], { session });

    // 3. 在庫引当
    for (const item of items) {
      await Product.updateOne(
        { sku: item.sku, stock: { $gte: item.qty } },
        { $inc: { stock: -item.qty } }
      ).session(session);
    }

    await session.commitTransaction();
    return order[0];
  } catch (error) {
    await session.abortTransaction();
    throw error;
  } finally {
    session.endSession();
  }
}

❓ よくある質問

Q deleteOneとdeleteManyで削除したデータは復元できますか?
A 直接的な復元方法はありません。削除されたドキュメントを復元するにはバックアップまたはoplog(MongoDB Atlasの場合)が必要です。本番環境では削除前に必ずバックアップを取るか、論理削除(isActive: falseを設定)を使用してください。
Q findOneAndDeleteはいつ使うべきですか?
A 削除したドキュメントの内容が必要な場合(例:キュータスクの消費)、または削除と検索の間の競合状態を回避したい場合に使用してください。単にドキュメントを削除したいだけならdeleteOneを使用してください。
Q Mongoose接続で「buffering timed out after 10000ms」エラーが発生します
A Mongooseは接続待ちをデフォルトで10秒間バッファリングします。接続が確立する前にクエリを実行した場合、このエラーが発生します。mongoose.connect()の完了を待つか、bufferCommands: falseオプションでバッファリングを無効化してください。
Q Mongooseのsave()とupdateOne()の違いは何ですか?
A save()はスキーマ検証、ミドルウェア、デフォルト値の生成を実行しますが、ドキュメント全体を書き込む必要があります。updateOne()は特定のフィールドのみを更新できますが、検証とミドルウェアはスキップします。検証が必要な場合はsave()を、パフォーマンス重視の場合はupdateOne()を使用してください。
Q dropとdeleteMany({})のどちらを使うべきですか?
A コレクション全体を削除してインデックスもクリアしたい場合はdrop()を使用してください。コレクション構造(インデックス、capped設定)を保持したい場合はdeleteMany({})を使用してください。drop()の方が高速です。

📖 まとめ


📝 練習問題

  1. 基礎問題(⭐)deleteOneを使用してSKU「PHONE-001」の商品を削除し、戻り値のdeletedCountを確認してください。
  2. 基礎問題(⭐)deleteManyを使用して30日以上前のログレコードを一括削除してください。
  3. 応用問題(⭐⭐)findOneAndDeleteを使用してメッセージキューを実装し、最も古いpendingメッセージを消費してください。
  4. 応用問題(⭐⭐):Mongooseで商品スキーマを定義し(必須フィールド、検証ルール、インデックスを含む)、CRUD操作を実装してください。
  5. チャレンジ(⭐⭐⭐):トランザクション付きの注文処理APIを実装(在庫チェック、注文作成、在庫引当を原子的に実行)し、完全なエラー処理とロールバックを含めてください。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%