Skip to content

Commit 8bbf734

Browse files
committed
add findOne
1 parent 468dfff commit 8bbf734

4 files changed

Lines changed: 1331 additions & 2 deletions

File tree

docs/findOne.md

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
# findOne 方法详细文档
2+
3+
## 概述
4+
5+
`findOne` 是 monSQLize 提供的基础查询方法,用于从 MongoDB 集合中查询第一条匹配的文档记录。支持查询条件、排序、投影和缓存等功能。
6+
7+
## 方法签名
8+
9+
```javascript
10+
async findOne(options = {})
11+
```
12+
13+
## 参数说明
14+
15+
### options 对象属性
16+
17+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
18+
|------|------|------|--------|------|
19+
| `query` | Object || `{}` | MongoDB 查询条件,如 `{ status: 'active', age: { $gt: 18 } }` |
20+
| `projection` | Object/Array || - | 字段投影配置,指定返回的字段 |
21+
| `sort` | Object || - | 排序规则,如 `{ createdAt: -1, name: 1 }` |
22+
| `hint` | Object/String || - | 指定查询使用的索引 |
23+
| `collation` | Object || - | 指定排序规则(用于字符串排序) |
24+
| `maxTimeMS` | Number || 全局配置 | 查询超时时间(毫秒) |
25+
| `cache` | Number || `0` | 缓存 TTL(毫秒),大于 0 时启用缓存 |
26+
| `explain` | Boolean/String || - | 返回查询执行计划,可选值:`true``'queryPlanner'``'executionStats'``'allPlansExecution'` |
27+
28+
### projection 配置
29+
30+
投影配置用于指定查询结果中包含或排除的字段,支持两种格式:
31+
32+
**对象格式**
33+
```javascript
34+
projection: {
35+
name: 1, // 包含 name 字段
36+
email: 1, // 包含 email 字段
37+
password: 0 // 排除 password 字段
38+
}
39+
```
40+
41+
**数组格式**
42+
```javascript
43+
projection: ['name', 'email', 'createdAt'] // 只返回这些字段(加上 _id)
44+
```
45+
46+
**注意**
47+
- MongoDB 不允许混合使用包含(1)和排除(0),除了 `_id` 字段
48+
- 数组格式会自动转换为包含模式
49+
- `_id` 字段默认总是包含,除非显式排除:`{ _id: 0 }`
50+
51+
### sort 配置
52+
53+
排序配置指定结果的排序方式:
54+
55+
```javascript
56+
sort: {
57+
createdAt: -1, // -1 表示降序
58+
name: 1, // 1 表示升序
59+
_id: 1 // 建议添加 _id 作为最后的排序字段,确保排序稳定
60+
}
61+
```
62+
63+
**性能建议**
64+
- 对于大数据集,确保排序字段上有索引
65+
- 避免对未索引的字段进行排序
66+
- 使用复合索引可以优化多字段排序
67+
68+
### hint 配置
69+
70+
强制 MongoDB 使用指定的索引:
71+
72+
```javascript
73+
// 使用索引名称
74+
hint: 'status_createdAt_idx'
75+
76+
// 使用索引定义
77+
hint: { status: 1, createdAt: -1 }
78+
```
79+
80+
**使用场景**
81+
- MongoDB 查询优化器选择了错误的索引
82+
- 需要强制使用特定索引以保证性能
83+
- 测试不同索引的性能差异
84+
85+
### collation 配置
86+
87+
指定字符串比较和排序的规则:
88+
89+
```javascript
90+
collation: {
91+
locale: 'zh', // 中文
92+
strength: 2, // 忽略大小写和重音符号
93+
caseLevel: false,
94+
numericOrdering: true // 数字字符串按数值排序
95+
}
96+
```
97+
98+
**常见场景**
99+
- 需要不区分大小写的查询和排序
100+
- 多语言环境下的正确排序
101+
- 数字字符串的自然排序
102+
103+
## 返回值
104+
105+
### 普通模式返回对象或 null
106+
107+
默认情况下,`findOne` 方法返回一个 Promise,resolve 为匹配的第一条文档或 null:
108+
109+
```javascript
110+
const user = await collection('users').findOne({
111+
query: { email: 'alice@example.com' }
112+
});
113+
114+
// user = { _id: '...', name: 'Alice', email: 'alice@example.com', ... }
115+
// 或 null(如果未找到)
116+
```
117+
118+
**返回值类型**`Promise<Object|null>`
119+
120+
### explain 模式返回执行计划
121+
122+
`explain` 为 true 或指定级别时,返回查询执行计划:
123+
124+
```javascript
125+
const plan = await collection('users').findOne({
126+
query: { email: 'alice@example.com' },
127+
explain: 'executionStats'
128+
});
129+
130+
// plan = {
131+
// queryPlanner: { ... },
132+
// executionStats: {
133+
// executionTimeMillis: 2,
134+
// totalDocsExamined: 1,
135+
// totalKeysExamined: 1,
136+
// ...
137+
// }
138+
// }
139+
```
140+
141+
**返回值类型**`Promise<Object>`
142+
143+
## 使用模式
144+
145+
### 1. 基础查询
146+
147+
最简单的查询方式,返回第一条匹配的文档:
148+
149+
```javascript
150+
// 根据 ID 查询用户
151+
const user = await collection('users').findOne({
152+
query: { _id: ObjectId('507f1f77bcf86cd799439011') }
153+
});
154+
155+
// 根据条件查询
156+
const activeUser = await collection('users').findOne({
157+
query: { status: 'active' },
158+
sort: { createdAt: -1 } // 获取最新的活跃用户
159+
});
160+
161+
// 指定返回字段
162+
const userProfile = await collection('users').findOne({
163+
query: { email: 'alice@example.com' },
164+
projection: { name: 1, email: 1, avatar: 1 }
165+
});
166+
```
167+
168+
**适用场景**
169+
- 根据唯一标识查询单条记录
170+
- 获取最新/最旧的记录
171+
- 检查记录是否存在
172+
173+
### 2. 复杂查询条件
174+
175+
使用 MongoDB 查询操作符构建复杂查询:
176+
177+
```javascript
178+
// 范围查询
179+
const order = await collection('orders').findOne({
180+
query: {
181+
amount: { $gte: 1000 },
182+
status: 'paid'
183+
},
184+
sort: { createdAt: -1 }
185+
});
186+
187+
// 逻辑组合查询
188+
const user = await collection('users').findOne({
189+
query: {
190+
$or: [
191+
{ role: 'admin' },
192+
{ level: { $gte: 10 } }
193+
],
194+
verified: true
195+
}
196+
});
197+
198+
// 数组查询
199+
const product = await collection('products').findOne({
200+
query: {
201+
tags: 'featured',
202+
'reviews.rating': { $gte: 4.5 }
203+
},
204+
sort: { rating: -1 }
205+
});
206+
```
207+
208+
### 3. 使用索引优化
209+
210+
通过 hint 强制使用索引,explain 查看执行计划:
211+
212+
```javascript
213+
// 强制使用索引
214+
const user = await collection('users').findOne({
215+
query: { email: 'alice@example.com' },
216+
hint: { email: 1 }
217+
});
218+
219+
// 查看执行计划
220+
const plan = await collection('users').findOne({
221+
query: { email: 'alice@example.com' },
222+
explain: 'executionStats'
223+
});
224+
```
225+
226+
**性能优化建议**
227+
- 为常用查询字段创建索引
228+
- 使用复合索引优化多条件查询
229+
- 定期分析慢查询并优化索引
230+
231+
### 4. 缓存使用
232+
233+
启用缓存以提升查询性能:
234+
235+
```javascript
236+
// 缓存 5 分钟
237+
const user = await collection('users').findOne({
238+
query: { _id: ObjectId('507f1f77bcf86cd799439011') },
239+
cache: 5 * 60 * 1000 // 5 分钟
240+
});
241+
```
242+
243+
**缓存策略**
244+
- 对频繁查询且数据变化不频繁的记录启用缓存
245+
- 设置合理的 TTL 时间
246+
- 注意缓存失效机制
247+
248+
## 错误处理
249+
250+
`findOne` 方法可能抛出以下错误:
251+
252+
```javascript
253+
try {
254+
const user = await collection('users').findOne({
255+
query: { email: 'alice@example.com' }
256+
});
257+
} catch (error) {
258+
if (error.code === 'NOT_CONNECTED') {
259+
console.error('数据库未连接');
260+
} else {
261+
console.error('查询失败:', error.message);
262+
}
263+
}
264+
```
265+
266+
**常见错误**
267+
- `NOT_CONNECTED`: 数据库未连接
268+
- 查询超时错误
269+
- 权限相关错误
270+
271+
## 最佳实践
272+
273+
1. **总是指定排序**:当有多条记录匹配时,确保返回结果的一致性
274+
2. **使用投影**:只返回需要的字段,减少网络传输和内存使用
275+
3. **合理使用缓存**:对读多写少的场景启用缓存
276+
4. **创建适当索引**:确保查询性能
277+
5. **处理 null 返回值**:检查查询结果是否为 null
278+
279+
## 相关方法
280+
281+
- `find()`: 查询多条记录
282+
- `count()`: 统计记录数量
283+
- `findPage()`: 分页查询
284+
- `invalidate()`: 使缓存失效

0 commit comments

Comments
 (0)