Files
leaudit-platform-frontend/auth_doc/前端对接文档-PostgREST查询参考.md
2025-11-18 11:06:24 +08:00

7.3 KiB
Raw Permalink Blame History

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的%
  • _: 匹配单个字符

示例:

// 查询标题以"合同"开头的文档
{ 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.{重要,紧急}' }

示例:

// 查询状态为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' }

示例:

// 查询deleted_at为null的文档(未删除)
{ deleted_at: 'is.null' }

// 查询deleted_at不为null的文档(已删除)
{ deleted_at: 'nt.null' }

排序

单字段排序

// 按创建时间升序
{ order: 'created_at.asc' }

// 按创建时间降序
{ order: 'created_at.desc' }

多字段排序

// 先按状态升序,再按创建时间降序
{ order: 'status.asc,created_at.desc' }

分页

Limit和Offset

// 每页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条记录。

解析示例:

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

字段选择

选择特定字段

// 只返回id, title, status字段
{ select: 'id,title,status' }

嵌套查询(外键关联)

PostgREST支持嵌套查询,但DocAuditAI暂未启用此功能。

高级查询

逻辑运算符

注意: 前端应避免使用orandnot参数,这些参数由后端自动生成(用于数据范围和交叉评查权限)。

复杂查询示例

// 查询状态为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:文档列表查询

// 需求:查询标题包含"合同"、状态为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:高级搜索

// 需求:搜索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:分页封装

// 通用分页函数
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. 始终使用分页

// ✅ 好的做法
{ limit: 10, offset: 0 }

// ❌ 不好的做法(返回所有数据)
{}

2. 只查询需要的字段

// ✅ 好的做法(只查询id和title)
{ select: 'id,title' }

// ❌ 不好的做法(查询所有字段)
{}

3. 使用索引字段进行过滤

优先使用已建立索引的字段(如id, user_id, ou_id, status)进行过滤,提升查询性能。

4. 避免过度模糊查询

// ✅ 好的做法(明确的过滤条件)
{ title: 'like.合同*' }

// ❌ 不好的做法(前后通配符,性能差)
{ title: 'like.*合同*' }

常见错误

错误1:运算符拼写错误

// ❌ 错误
{ status: 'equal.active' }  // 应该是 eq

// ✅ 正确
{ status: 'eq.active' }

错误2:日期格式错误

// ❌ 错误
{ created_at: 'gte.2025/01/01' }  // 格式错误

// ✅ 正确
{ created_at: 'gte.2025-01-01' }  // ISO 8601格式

错误3in运算符语法错误

// ❌ 错误
{ status: 'in.active,pending' }  // 缺少括号

// ✅ 正确
{ status: 'in.(active,pending)' }

参考资料