Files
Cloud-book/数据库/MongoDB_2025/MongoDB进阶查询.md
2025-08-27 17:10:05 +08:00

167 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 查询进阶
本章节将带大家深入了解 MongoDB 强大的查询功能,包括使用查询操作符、投影、排序、分页以及正则表达式查询,可以更精确、更高效地从数据库中检索数据。
---
## 查询操作符
查询操作符是 MongoDB 查询语言的核心,它们可以帮助大家构建更复杂的查询条件。
### 比较操作符
| 操作符 | 描述 | 示例 |
| :--- | :--- | :--- |
| `$eq` | 等于 (Equal) | `db.inventory.find({ qty: { $eq: 20 } })` |
| `$ne` | 不等于 (Not Equal) | `db.inventory.find({ qty: { $ne: 20 } })` |
| `$gt` | 大于 (Greater Than) | `db.inventory.find({ qty: { $gt: 20 } })` |
| `$gte` | 大于等于 (Greater Than or Equal) | `db.inventory.find({ qty: { $gte: 20 } })` |
| `$lt` | 小于 (Less Than) | `db.inventory.find({ qty: { $lt: 20 } })` |
| `$lte` | 小于等于 (Less Than or Equal) | `db.inventory.find({ qty: { $lte: 20 } })` |
| `$in` | 在指定数组内 (In) | `db.inventory.find({ qty: { $in: [5, 15] } })` |
| `$nin` | 不在指定数组内 (Not In) | `db.inventory.find({ qty: { $nin: [5, 15] } })` |
### 逻辑操作符
| 操作符 | 描述 | 示例 |
| :--- | :--- | :--- |
| `$and` | 逻辑与,连接多个查询条件 | `db.inventory.find({ $and: [{ qty: { $lt: 20 } }, { price: { $gt: 10 } }] })` |
| `$or` | 逻辑或,满足任一查询条件 | `db.inventory.find({ $or: [{ qty: { $lt: 20 } }, { price: { $gt: 50 } }] })` |
| `$nor` | 逻辑非或,所有条件都不满足 | `db.inventory.find({ $nor: [{ price: 1.99 }, { sale: true }] })` |
| `$not` | 逻辑非,对指定条件取反 | `db.inventory.find({ price: { $not: { $gt: 1.99 } } })` |
### 元素操作符
| 操作符 | 描述 | 示例 |
| :--- | :--- | :--- |
| `$exists` | 判断字段是否存在 | `db.inventory.find({ qty: { $exists: true } })` |
| `$type` | 判断字段的数据类型 | `db.inventory.find({ qty: { $type: "number" } })` |
### 数组操作符
| 操作符 | 描述 | 示例 |
| :--- | :--- | :--- |
| `$all` | 匹配包含所有指定元素的数组 | `db.inventory.find({ tags: { $all: ["appliance", "school"] } })` |
| `$elemMatch` | 数组中至少有一个元素满足所有指定条件 | `db.inventory.find({ results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } })` |
| `$size` | 匹配指定大小的数组 | `db.inventory.find({ tags: { $size: 3 } })` |
---
## 投影Projection
投影用于限制查询结果中返回的字段,可以减少网络传输的数据量,并保护敏感字段。
- **包含字段**: 在 `find()` 方法的第二个参数中,将需要返回的字段设置为 `1`
```javascript
// 只返回 name 和 price 字段_id 默认返回
db.products.find({}, { name: 1, price: 1 })
```
- **排除字段**: 将不需要返回的字段设置为 `0`。
```javascript
// 返回除 description 之外的所有字段
db.products.find({}, { description: 0 })
```
- **排除 `_id` 字段**:
```javascript
db.products.find({}, { name: 1, price: 1, _id: 0 })
```
---
## 排序Sorting
使用 `sort()` 方法对查询结果进行排序。
- **升序 (Ascending)**: 将字段值设置为 `1`。
- **降序 (Descending)**: 将字段值设置为 `-1`。
```javascript
// 按价格升序排序
db.products.find().sort({ price: 1 })
// 按库存降序、名称升序排序
db.products.find().sort({ stock: -1, name: 1 })
```
---
## 分页Pagination
通过组合使用 `limit()` 和 `skip()` 方法,可以实现对查询结果的分页。
- **`limit()`**: 限制返回的文档数量。
- **`skip()`**: 跳过指定数量的文档。
```javascript
// 获取第 2 页数据,每页 10 条 (跳过前 10 条,返回 10 条)
db.products.find().skip(10).limit(10)
```
**注意**: 对于大数据量的集合,使用 `skip()` 进行深度分页可能会有性能问题。在这种情况下,建议使用基于范围的查询(如使用 `_id` 或时间戳)。
---
## 正则表达式查询
MongoDB 支持使用 PCRE (Perl Compatible Regular Expression) 语法的正则表达式进行字符串匹配。
```javascript
// 查询 name 字段以 'A' 开头的文档 (不区分大小写)
db.products.find({ name: { $regex: '^A', $options: 'i' } })
// 查询 name 字段包含 'pro' 的文档
db.products.find({ name: /pro/ })
```
---
## 实践操作
假设有一个 `students` 集合,包含以下字段:`name`, `age`, `major`, `gpa`, `courses` (数组)。
### 需求描述
1. **查询练习**:
- 查询所有主修 'Computer Science' 且 GPA 大于 3.5 的学生。
- 查询年龄在 20 到 22 岁之间(含)的学生。
- 查询选修了 'Database Systems' 和 'Data Structures' 两门课的学生。
2. **投影练习**:
- 只返回学生的姓名和专业。
3. **排序和分页练习**:
- 按 GPA 降序显示前 10 名学生。
4. **正则表达式练习**:
- 查询所有姓 'Li' 的学生。
### 实践细节和结果验证
```javascript
// 1. 查询练习
// 查询所有主修 'Computer Science' 且 GPA 大于 3.5 的学生
db.students.find({ major: 'Computer Science', gpa: { $gt: 3.5 } });
// 查询年龄在 20 到 22 岁之间(含)的学生
db.students.find({ age: { $gte: 20, $lte: 22 } });
// 查询选修了 'Database Systems' 和 'Data Structures' 两门课的学生
db.students.find({ courses: { $all: ['Database Systems', 'Data Structures'] } });
// 2. 投影练习
// 只返回学生的姓名和专业
db.students.find({}, { name: 1, major: 1, _id: 0 });
// 3. 排序和分页练习
// 按 GPA 降序显示前 10 名学生
db.students.find().sort({ gpa: -1 }).limit(10);
// 4. 正则表达式练习
// 查询所有姓 'Li' 的学生
db.students.find({ name: /^Li/ });
```