Skip to content

Commit c78ecfd

Browse files
committed
feaet:添加findAndUpdate详细操作指南
1 parent 1abca17 commit c78ecfd

4 files changed

Lines changed: 810 additions & 1 deletion

File tree

docs/INDEX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
| 文档 | 方法 | 说明 |
6767
|------|------|------|
6868
| [update-operations.md](update-operations.md) | 所有更新方法 | 更新操作完整指南 |
69+
| [upsert-guide.md](upsert-guide.md) | **Upsert 操作指南** | **不存在就插入,存在则更新 - 完整指南 ⭐** |
6970
| [update-one.md](update-one.md) | `updateOne()` | 更新单个文档 |
7071
| [update-many.md](update-many.md) | `updateMany()` | 批量更新文档 |
7172
| [update-aggregation.md](update-aggregation.md) | **🎉 Update 聚合管道 - 字段间计算、条件赋值(v1.0.8+)🆕** |

docs/find-one-and-update.md

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,10 @@ const user = await collection("users").findOneAndUpdate(
286286
// user 只包含 _id, name, loginCount
287287
```
288288

289-
### 使用 upsert
289+
### 使用 upsert(不存在就插入,存在则更新)⭐
290290

291291
```javascript
292+
// 基本用法:计数器示例
292293
const counter = await collection("counters").findOneAndUpdate(
293294
{ counterName: "pageViews" },
294295
{ $inc: { value: 1 } },
@@ -300,6 +301,119 @@ const counter = await collection("counters").findOneAndUpdate(
300301
// 如果不存在会创建新文档
301302
```
302303

304+
#### Upsert 详细说明
305+
306+
**upsert = update + insert** 的组合:
307+
-**存在**:执行更新操作
308+
-**不存在**:插入新文档
309+
310+
**使用场景**
311+
312+
```javascript
313+
// 场景 1:用户配置(不存在则创建默认配置)
314+
const userConfig = await collection("user_configs").findOneAndUpdate(
315+
{ userId: "user123" },
316+
{
317+
$set: {
318+
theme: "dark",
319+
language: "zh-CN",
320+
updatedAt: new Date()
321+
},
322+
$setOnInsert: {
323+
// 仅在插入时设置
324+
createdAt: new Date(),
325+
defaultSettings: true
326+
}
327+
},
328+
{
329+
upsert: true,
330+
returnDocument: "after"
331+
}
332+
);
333+
334+
// 场景 2:统计数据(自动初始化)
335+
const stats = await collection("daily_stats").findOneAndUpdate(
336+
{
337+
date: "2026-01-28",
338+
userId: "user123"
339+
},
340+
{
341+
$inc: { pageViews: 1, loginCount: 1 }
342+
},
343+
{
344+
upsert: true,
345+
returnDocument: "after"
346+
}
347+
);
348+
// 不存在时会创建:{ date: "2026-01-28", userId: "user123", pageViews: 1, loginCount: 1 }
349+
350+
// 场景 3:缓存更新(不存在则缓存新数据)
351+
const cache = await collection("cache").findOneAndUpdate(
352+
{ key: "user:profile:123" },
353+
{
354+
$set: {
355+
value: profileData,
356+
expireAt: new Date(Date.now() + 3600000) // 1小时后过期
357+
}
358+
},
359+
{
360+
upsert: true,
361+
returnDocument: "after"
362+
}
363+
);
364+
365+
// 场景 4:商品库存(自动创建库存记录)
366+
const inventory = await collection("inventory").findOneAndUpdate(
367+
{ productId: "prod-456" },
368+
{
369+
$inc: { quantity: -1 }, // 减少库存
370+
$set: { lastUpdated: new Date() }
371+
},
372+
{
373+
upsert: true,
374+
returnDocument: "after"
375+
}
376+
);
377+
```
378+
379+
**⚠️ Upsert 注意事项**
380+
381+
```javascript
382+
// ❌ 错误:使用 $setOnInsert 但忘记 upsert
383+
const doc = await collection("users").findOneAndUpdate(
384+
{ userId: "user123" },
385+
{ $setOnInsert: { createdAt: new Date() } }
386+
// 缺少 upsert: true,$setOnInsert 不会生效
387+
);
388+
389+
// ✅ 正确:同时使用 $set 和 $setOnInsert
390+
const doc = await collection("users").findOneAndUpdate(
391+
{ userId: "user123" },
392+
{
393+
$set: { lastLogin: new Date() }, // 每次都更新
394+
$setOnInsert: { createdAt: new Date() } // 仅插入时设置
395+
},
396+
{ upsert: true }
397+
);
398+
399+
// ✅ 正确:获取 upsert 的 _id
400+
const result = await collection("users").findOneAndUpdate(
401+
{ email: "new@example.com" },
402+
{ $set: { name: "New User" } },
403+
{
404+
upsert: true,
405+
returnDocument: "after",
406+
includeResultMetadata: true
407+
}
408+
);
409+
410+
if (result.lastErrorObject.upserted) {
411+
console.log("创建了新文档,_id:", result.lastErrorObject.upserted);
412+
} else {
413+
console.log("更新了现有文档");
414+
}
415+
```
416+
303417
### 获取完整元数据
304418

305419
```javascript

0 commit comments

Comments
 (0)