bfe39e45a9
5. 修改统一认证登录和管理员登录是通过接口形式进行,存储返回的accessToken。 6. 修改交叉评查的部分样式
317 lines
7.3 KiB
Markdown
317 lines
7.3 KiB
Markdown
# PostgREST查询参考
|
||
|
||
## 过滤运算符完整列表
|
||
|
||
### 比较运算符
|
||
|
||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||
|--------|------|---------------|----------------|
|
||
| eq | 等于 | `field=eq.value` | `{ field: 'eq.value' }` |
|
||
| neq | 不等于 | `field=neq.value` | `{ field: 'neq.value' }` |
|
||
| gt | 大于 | `field=gt.value` | `{ field: 'gt.100' }` |
|
||
| gte | 大于等于 | `field=gte.value` | `{ field: 'gte.100' }` |
|
||
| lt | 小于 | `field=lt.value` | `{ field: 'lt.100' }` |
|
||
| lte | 小于等于 | `field=lte.value` | `{ field: 'lte.100' }` |
|
||
|
||
### 模式匹配运算符
|
||
|
||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||
|--------|------|---------------|----------------|
|
||
| like | 模糊匹配(区分大小写) | `field=like.*pattern*` | `{ field: 'like.*测试*' }` |
|
||
| ilike | 模糊匹配(不区分大小写) | `field=ilike.*pattern*` | `{ field: 'ilike.*TEST*' }` |
|
||
|
||
**模式匹配通配符**:
|
||
- `*`: 匹配任意字符(等同于SQL的`%`)
|
||
- `_`: 匹配单个字符
|
||
|
||
**示例**:
|
||
```javascript
|
||
// 查询标题以"合同"开头的文档
|
||
{ title: 'like.合同*' }
|
||
|
||
// 查询标题以"合同"结尾的文档
|
||
{ title: 'like.*合同' }
|
||
|
||
// 查询标题包含"合同"的文档
|
||
{ title: 'like.*合同*' }
|
||
|
||
// 不区分大小写查找
|
||
{ title: 'ilike.*contract*' }
|
||
```
|
||
|
||
### 列表运算符
|
||
|
||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||
|--------|------|---------------|----------------|
|
||
| in | 在列表中 | `field=in.(value1,value2,...)` | `{ field: 'in.(active,pending)' }` |
|
||
| cs | 包含(数组字段) | `field=cs.{value1,value2}` | `{ tags: 'cs.{重要,紧急}' }` |
|
||
| cd | 被包含(数组字段) | `field=cd.{value1,value2}` | `{ tags: 'cd.{重要,紧急}' }` |
|
||
| ov | 重叠(数组字段) | `field=ov.{value1,value2}` | `{ tags: 'ov.{重要,紧急}' }` |
|
||
|
||
**示例**:
|
||
```javascript
|
||
// 查询状态为active或pending的文档
|
||
{ status: 'in.(active,pending)' }
|
||
|
||
// 查询ID在[1, 2, 3]中的文档
|
||
{ id: 'in.(1,2,3)' }
|
||
|
||
// 查询标签包含"重要"和"紧急"的文档(数组字段)
|
||
{ tags: 'cs.{重要,紧急}' }
|
||
```
|
||
|
||
### Null检查运算符
|
||
|
||
| 运算符 | 说明 | PostgREST语法 | JavaScript示例 |
|
||
|--------|------|---------------|----------------|
|
||
| is | 是null | `field=is.null` | `{ field: 'is.null' }` |
|
||
| nt | 不是null | `field=nt.null` (或 `is.not.null`) | `{ field: 'nt.null' }` |
|
||
|
||
**示例**:
|
||
```javascript
|
||
// 查询deleted_at为null的文档(未删除)
|
||
{ deleted_at: 'is.null' }
|
||
|
||
// 查询deleted_at不为null的文档(已删除)
|
||
{ deleted_at: 'nt.null' }
|
||
```
|
||
|
||
## 排序
|
||
|
||
### 单字段排序
|
||
|
||
```javascript
|
||
// 按创建时间升序
|
||
{ order: 'created_at.asc' }
|
||
|
||
// 按创建时间降序
|
||
{ order: 'created_at.desc' }
|
||
```
|
||
|
||
### 多字段排序
|
||
|
||
```javascript
|
||
// 先按状态升序,再按创建时间降序
|
||
{ order: 'status.asc,created_at.desc' }
|
||
```
|
||
|
||
## 分页
|
||
|
||
### Limit和Offset
|
||
|
||
```javascript
|
||
// 每页10条,第1页
|
||
{ limit: 10, offset: 0 }
|
||
|
||
// 每页10条,第2页
|
||
{ limit: 10, offset: 10 }
|
||
|
||
// 每页20条,第3页
|
||
{ limit: 20, offset: 40 }
|
||
```
|
||
|
||
### 获取总数
|
||
|
||
PostgREST会在响应头中返回`Content-Range`,包含总记录数:
|
||
|
||
```
|
||
Content-Range: 0-9/50
|
||
```
|
||
表示:返回第0-9条记录,总共50条记录。
|
||
|
||
**解析示例**:
|
||
```javascript
|
||
const response = await apiClient.get('/postgrest/documents', {
|
||
params: { limit: 10, offset: 0 }
|
||
});
|
||
|
||
const contentRange = response.headers['content-range'];
|
||
const total = parseInt(contentRange.split('/')[1]); // 50
|
||
```
|
||
|
||
## 字段选择
|
||
|
||
### 选择特定字段
|
||
|
||
```javascript
|
||
// 只返回id, title, status字段
|
||
{ select: 'id,title,status' }
|
||
```
|
||
|
||
### 嵌套查询(外键关联)
|
||
|
||
PostgREST支持嵌套查询,但DocAuditAI暂未启用此功能。
|
||
|
||
## 高级查询
|
||
|
||
### 逻辑运算符
|
||
|
||
**注意**: 前端应避免使用`or`、`and`、`not`参数,这些参数由后端自动生成(用于数据范围和交叉评查权限)。
|
||
|
||
### 复杂查询示例
|
||
|
||
```javascript
|
||
// 查询状态为active且创建时间在2025年之后的文档,按创建时间降序,每页10条
|
||
const params = {
|
||
status: 'eq.active',
|
||
created_at: 'gte.2025-01-01',
|
||
order: 'created_at.desc',
|
||
limit: 10,
|
||
offset: 0
|
||
};
|
||
|
||
const response = await apiClient.get('/postgrest/documents', { params });
|
||
```
|
||
|
||
## 完整示例
|
||
|
||
### 示例1:文档列表查询
|
||
|
||
```javascript
|
||
// 需求:查询标题包含"合同"、状态为active的文档,
|
||
// 按创建时间降序排列,每页20条,第2页
|
||
|
||
async function getDocumentList() {
|
||
const response = await apiClient.get('/postgrest/documents', {
|
||
params: {
|
||
title: 'ilike.*合同*',
|
||
status: 'eq.active',
|
||
order: 'created_at.desc',
|
||
limit: 20,
|
||
offset: 20 // 第2页
|
||
}
|
||
});
|
||
|
||
return {
|
||
data: response.data,
|
||
total: parseInt(response.headers['content-range'].split('/')[1])
|
||
};
|
||
}
|
||
```
|
||
|
||
### 示例2:高级搜索
|
||
|
||
```javascript
|
||
// 需求:搜索2025年创建的、状态为active或pending的文档
|
||
|
||
async function advancedSearch() {
|
||
const response = await apiClient.get('/postgrest/documents', {
|
||
params: {
|
||
status: 'in.(active,pending)',
|
||
created_at: 'gte.2025-01-01',
|
||
created_at: 'lt.2026-01-01', // 注意:PostgREST会组合多个同名参数
|
||
order: 'created_at.desc'
|
||
}
|
||
});
|
||
|
||
return response.data;
|
||
}
|
||
```
|
||
|
||
### 示例3:分页封装
|
||
|
||
```javascript
|
||
// 通用分页函数
|
||
async function fetchPaginated(table, page, pageSize, filters = {}) {
|
||
const params = {
|
||
limit: pageSize,
|
||
offset: (page - 1) * pageSize,
|
||
...filters
|
||
};
|
||
|
||
const response = await apiClient.get(`/postgrest/${table}`, { params });
|
||
|
||
const contentRange = response.headers['content-range'];
|
||
const total = contentRange ? parseInt(contentRange.split('/')[1]) : 0;
|
||
|
||
return {
|
||
data: response.data,
|
||
total: total,
|
||
page: page,
|
||
pageSize: pageSize,
|
||
totalPages: Math.ceil(total / pageSize)
|
||
};
|
||
}
|
||
|
||
// 使用示例
|
||
const result = await fetchPaginated('documents', 1, 10, {
|
||
status: 'eq.active',
|
||
order: 'created_at.desc'
|
||
});
|
||
|
||
console.log(`共${result.total}条记录,第${result.page}/${result.totalPages}页`);
|
||
```
|
||
|
||
## 性能优化建议
|
||
|
||
### 1. 始终使用分页
|
||
|
||
```javascript
|
||
// ✅ 好的做法
|
||
{ limit: 10, offset: 0 }
|
||
|
||
// ❌ 不好的做法(返回所有数据)
|
||
{}
|
||
```
|
||
|
||
### 2. 只查询需要的字段
|
||
|
||
```javascript
|
||
// ✅ 好的做法(只查询id和title)
|
||
{ select: 'id,title' }
|
||
|
||
// ❌ 不好的做法(查询所有字段)
|
||
{}
|
||
```
|
||
|
||
### 3. 使用索引字段进行过滤
|
||
|
||
优先使用已建立索引的字段(如id, user_id, ou_id, status)进行过滤,提升查询性能。
|
||
|
||
### 4. 避免过度模糊查询
|
||
|
||
```javascript
|
||
// ✅ 好的做法(明确的过滤条件)
|
||
{ title: 'like.合同*' }
|
||
|
||
// ❌ 不好的做法(前后通配符,性能差)
|
||
{ title: 'like.*合同*' }
|
||
```
|
||
|
||
## 常见错误
|
||
|
||
### 错误1:运算符拼写错误
|
||
|
||
```javascript
|
||
// ❌ 错误
|
||
{ status: 'equal.active' } // 应该是 eq
|
||
|
||
// ✅ 正确
|
||
{ status: 'eq.active' }
|
||
```
|
||
|
||
### 错误2:日期格式错误
|
||
|
||
```javascript
|
||
// ❌ 错误
|
||
{ created_at: 'gte.2025/01/01' } // 格式错误
|
||
|
||
// ✅ 正确
|
||
{ created_at: 'gte.2025-01-01' } // ISO 8601格式
|
||
```
|
||
|
||
### 错误3:in运算符语法错误
|
||
|
||
```javascript
|
||
// ❌ 错误
|
||
{ status: 'in.active,pending' } // 缺少括号
|
||
|
||
// ✅ 正确
|
||
{ status: 'in.(active,pending)' }
|
||
```
|
||
|
||
## 参考资料
|
||
|
||
- [PostgREST官方文档](https://postgrest.org/en/stable/)
|
||
- [PostgREST API查询语法](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows)
|