Node.js 教程
MongoDB 增删改查与进阶
本教程共 76 篇 · 第 51 篇 · 更新于 2026-07-25 · 约 3 分钟阅读
Node.jsMongoDBCRUD聚合NoSQL
51. MongoDB 增删改查与进阶
本节目标:MongoDB 文档操作、查询条件和聚合管道。
MongoDB 的查询风格和 SQL 完全不同。没有 SELECT * FROM,取而代之的是 find() 和灵活的条件对象。本章把 CRUD 过一遍,再看排序、聚合等进阶操作。
前置准备
Docker 起 MongoDB:
docker run -d -p 27017:27017 --name mongo mongo:7
连接代码(沿用第 48 章的封装):
import { MongoClient } from 'mongodb';
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('shop');
const products = db.collection('products');
Create:插入文档
MongoDB 里一条记录叫「文档」,类似 JSON 对象。
// 插入单条
await products.insertOne({
name: '无线鼠标',
price: 99,
tags: ['数码', '办公'],
stock: 100,
createdAt: new Date()
});
// 插入多条
await products.insertMany([
{ name: '机械键盘', price: 299, tags: ['数码'], stock: 50 },
{ name: '显示器支架', price: 159, tags: ['办公'], stock: 30 }
]);
NoteMongoDB 会自动给每个文档生成
_id字段(ObjectId 类型),除非你自己传。这个字段全局唯一,可以当作主键用。
Read:查询文档
基础查询
// 等值匹配
await products.findOne({ name: '无线鼠标' });
// 查多条
const list = await products.find({ tags: '数码' }).toArray();
比较操作符
await products.find({ price: { $gte: 100, $lte: 300 } }).toArray(); // 100~300
await products.find({ stock: { $gt: 0 } }).toArray(); // 有库存
await products.find({ tags: { $in: ['数码', '游戏'] } }).toArray(); // 标签在列表中
常见操作符:
| 操作符 | 含义 |
|---|---|
$eq | 等于 |
$ne | 不等于 |
$gt / $gte | 大于 / 大于等于 |
$lt / $lte | 小于 / 小于等于 |
$in / $nin | 在 / 不在数组中 |
逻辑组合
// AND(默认就是 AND)
await products.find({ price: { $gte: 100 }, stock: { $gt: 0 } }).toArray();
// OR
await products.find({
$or: [{ price: { $lt: 50 } }, { stock: { $gt: 200 } }]
}).toArray();
Update:更新文档
// 局部更新($set 只改指定字段,其他保留)
await products.updateOne(
{ name: '无线鼠标' },
{ $set: { price: 89, stock: 95 } }
);
// 不存在则插入(upsert)
await products.updateOne(
{ name: '新款耳机' },
{ $set: { price: 199, stock: 20 } },
{ upsert: true }
);
// 数字字段原子增减
await products.updateOne(
{ name: '无线鼠标' },
{ $inc: { stock: -1 } } // 库存减 1
);
Warning
updateOne默认只改匹配的第一条。如果想像 SQL 的UPDATE ... WHERE那样改多条,用updateMany。
Delete:删除文档
// 删单条
await products.deleteOne({ name: '显示器支架' });
// 删多条
await products.deleteMany({ stock: 0 });
和 MySQL 一样,生产环境建议软删除:
await products.updateOne(
{ _id: someId },
{ $set: { deletedAt: new Date() } }
);
查询时统一加上 deletedAt: { $exists: false } 过滤掉已删除的。
排序与分页
// 按价格升序,再按库存降序
const list = await products
.find({ stock: { $gt: 0 } })
.sort({ price: 1, stock: -1 })
.skip(20) // 跳过前 20 条
.limit(10) // 取 10 条
.toArray();
skip + limit 是 MongoDB 的分页方式。数据量大时 skip 会变慢,可以考虑用 _id 范围查询替代:
const lastId = '...'; // 上一页最后一条的 _id
await products.find({ _id: { $gt: lastId } }).limit(10).toArray();
聚合管道
聚合管道(Aggregation Pipeline)是 MongoDB 的强大武器,类似 Linux 的管道,把数据一步步加工。
统计每个标签下的商品数量和平均价格:
const result = await products.aggregate([
{ $unwind: '$tags' }, // 把 tags 数组拆成多条
{ $group: {
_id: '$tags',
count: { $sum: 1 },
avgPrice: { $avg: '$price' }
}},
{ $sort: { count: -1 } }
]).toArray();
常用阶段:
| 阶段 | 作用 |
|---|---|
$match | 过滤文档(类似 WHERE) |
$group | 分组聚合 |
$sort | 排序 |
$limit / $skip | 分页 |
$project | 选择字段、计算新字段 |
$lookup | 左外连接(类似 JOIN) |