跳到主要内容

Filter API 高级过滤查询

v1.1.22+

filter API 是 Lovrabet SDK 提供的强大数据查询接口,支持复杂条件筛选、字段选择、排序和分页,是进行数据列表查询的推荐方式。

前置条件

开始之前,请确保已完成 SDK 配置。推荐使用 CLI 自动生成配置

以下示例使用别名方式 client.models.users 以便阅读,也可以使用标准方式 client.models.dataset_xxx(功能完全一致)。

全模式支持

从 v1.1.22 版本开始,filter API 同时支持 OpenAPI 模式WebAPI 模式

🎯 主要功能

  • 复杂条件查询 - 支持多条件组合、范围查询、模糊匹配等
  • 字段选择 - 只返回需要的字段,减少数据传输量
  • 灵活排序 - 支持多字段排序
  • 分页查询 - 内置分页支持
  • 类型安全 - 完整的 TypeScript 类型支持

📝 API 签名

async filter<T = any>(params?: FilterParams): Promise<ListResponse<T>>

参数说明

interface FilterParams {
where?: WhereCondition; // 查询条件
select?: string[]; // 选择返回的字段
orderBy?: SortList; // 排序规则
currentPage?: number; // 当前页码(从 1 开始,默认: 1)
pageSize?: number; // 每页数量(默认: 20)
}

返回值

interface ListResponse<T> {
tableData: T[]; // 数据列表
total: number; // 总记录数
currentPage: number; // 当前页码
pageSize: number; // 每页数量
}

🔍 Where 条件详解

条件操作符

filter API 支持以下条件操作符(所有操作符都以 $ 开头):

操作符说明示例
$eq等于{ age: { $eq: 18 } }
$ne不等于{ status: { $ne: 'deleted' } }
$gte / $gteq大于等于{ age: { $gte: 18 } }
$lte / $lteq小于等于{ age: { $lte: 65 } }
$in在集合内{ country: { $in: ['中国', '美国'] } }
$contain包含(模糊匹配){ name: { $contain: 'hello' } }
$startWith以...开头{ email: { $startWith: 'admin' } }
$endWith以...结尾{ filename: { $endWith: '.pdf' } }
$ 符号的作用

$ 开头的表达式是 filter API 的特殊操作符,用于表示查询条件类型。这是一种通用的查询语言约定,可以避免与普通字段名冲突。

逻辑连接符

支持 $and$or 进行条件组合:

连接符说明示例
$and且(所有条件都满足){ $and: [条件1, 条件2] }
$or或(任一条件满足){ $or: [条件1, 条件2] }

💡 使用示例

基础查询

简单等值查询

// 查询年龄为 18 岁的用户
const result = await client.models.users.filter({
where: {
age: { $eq: 18 },
},
});

范围查询

// 查询年龄在 18-45 岁之间的用户
const result = await client.models.users.filter({
where: {
age: {
$gte: 18, // 大于等于 18
$lte: 45, // 小于等于 45
},
},
});

集合查询

// 查询来自中国、美国或日本的用户
const result = await client.models.users.filter({
where: {
country: {
$in: ["中国", "美国", "日本"],
},
},
});

模糊匹配

// 查询名字包含 "hello" 的用户
const result = await client.models.users.filter({
where: {
name: { $contain: "hello" },
},
});

// 查询邮箱以 "admin" 开头的用户
const result = await client.models.users.filter({
where: {
email: { $startWith: "admin" },
},
});

复合条件查询

AND 条件组合

// 查询 18-45 岁且来自中国的 VIP 用户
const result = await client.models.users.filter({
where: {
$and: [
{ age: { $gte: 18, $lte: 45 } },
{ country: { $eq: "中国" } },
{ vip: { $ne: null } },
],
},
});

OR 条件组合

// 查询年龄小于 18 或大于 65 的用户
const result = await client.models.users.filter({
where: {
$or: [{ age: { $lte: 18 } }, { age: { $gte: 65 } }],
},
});

混合逻辑

// 查询 VIP 用户或者活跃且来自中国的普通用户
const result = await client.models.users.filter({
where: {
$or: [
{ vip: { $eq: true } },
{
$and: [{ active: { $eq: true } }, { country: { $eq: "中国" } }],
},
],
},
});

字段选择

使用 select 参数只返回需要的字段,提高查询效率:

// 只返回 id、name、email 字段
const result = await client.models.users.filter({
where: {
country: { $eq: "中国" },
},
select: ["id", "name", "email"],
});

console.log(result.tableData);
// [
// { id: 1, name: '张三', email: 'zhangsan@example.com' },
// { id: 2, name: '李四', email: 'lisi@example.com' }
// ]
性能优化

当数据表字段很多但只需要其中几个字段时,使用 select 可以显著减少网络传输数据量和查询时间。

排序

使用 orderBy 参数指定排序规则:

// 单字段排序:按最后登录时间降序
const result = await client.models.users.filter({
where: {
country: { $eq: "中国" },
},
orderBy: [{ lastLoginAt: "desc" }],
});

// 多字段排序:先按优先级降序,再按创建时间降序
const result = await client.models.tasks.filter({
where: {
status: { $ne: "completed" },
},
orderBy: [
{ priority: "desc" }, // 第一优先级
{ createTime: "desc" }, // 第二优先级
{ name: "asc" }, // 第三优先级
],
});

分页

使用 currentPagepageSize 参数进行分页:

// 获取第 2 页,每页 50 条记录
const result = await client.models.users.filter({
where: {
country: { $eq: "中国" },
},
currentPage: 2,
pageSize: 50,
});

console.log(`总数: ${result.total}`);
console.log(`当前页: ${result.currentPage}`);
console.log(`每页数量: ${result.pageSize}`);
console.log(`数据:`, result.tableData);

🎨 完整示例

示例 1:用户管理系统

import { createClient } from "@lovrabet/sdk";

const client = createClient();

// 查询活跃的中国 VIP 用户,年龄在 18-45 岁之间
// 只返回必要字段,按最后登录时间倒序排列
const result = await client.models.users.filter({
where: {
$and: [
{ age: { $gte: 18, $lte: 45 } },
{ country: { $in: ["中国", "美国", "日本"] } },
{ vip: { $ne: null } },
{ active: { $eq: true } },
{ name: { $contain: "hello" } },
],
},
select: ["id", "name", "age", "country", "lastLoginAt", "email"],
orderBy: [{ lastLoginAt: "desc" }, { name: "asc" }],
currentPage: 1,
pageSize: 20,
});

console.log(`找到 ${result.total} 个符合条件的用户`);
result.tableData.forEach((user) => {
console.log(`${user.name} (${user.age}岁) - ${user.email}`);
});

示例 2:订单查询

// 查询最近 30 天内,金额大于 100 且状态为待支付或处理中的订单
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

const result = await client.models.orders.filter({
where: {
$and: [
{ createTime: { $gte: thirtyDaysAgo.toISOString() } },
{ amount: { $gte: 100 } },
{
$or: [
{ status: { $eq: "pending" } },
{ status: { $eq: "processing" } },
],
},
],
},
select: ["id", "orderNo", "amount", "status", "createTime", "customerName"],
orderBy: [{ amount: "desc" }, { createTime: "desc" }],
currentPage: 1,
pageSize: 50,
});

示例 3:搜索功能

// 实现一个搜索功能:在标题或内容中包含关键词
async function searchArticles(keyword: string, page: number = 1) {
return await client.models.articles.filter({
where: {
$or: [
{ title: { $contain: keyword } },
{ content: { $contain: keyword } },
],
},
select: ["id", "title", "summary", "author", "publishTime"],
orderBy: [{ publishTime: "desc" }],
currentPage: page,
pageSize: 10,
});
}

// 使用搜索
const results = await searchArticles("人工智能", 1);
console.log(`搜索到 ${results.total} 篇文章`);

示例 4:React 组件集成

import { useState, useEffect } from "react";
import { client } from "./api/client";

function UserList() {
const [users, setUsers] = useState([]);
const [total, setTotal] = useState(0);
const [currentPage, setCurrentPage] = useState(1);
const [loading, setLoading] = useState(false);

// 查询条件
const [filters, setFilters] = useState({
country: "中国",
minAge: 18,
maxAge: 65,
vipOnly: false,
});

useEffect(() => {
loadUsers();
}, [currentPage, filters]);

const loadUsers = async () => {
setLoading(true);
try {
const result = await client.models.users.filter({
where: {
$and: [
{ age: { $gte: filters.minAge, $lte: filters.maxAge } },
{ country: { $eq: filters.country } },
...(filters.vipOnly ? [{ vip: { $ne: null } }] : []),
],
},
select: ["id", "name", "age", "email", "country", "vip"],
orderBy: [{ vip: "desc" }, { age: "asc" }],
currentPage,
pageSize: 20,
});

setUsers(result.tableData);
setTotal(result.total);
} catch (error) {
console.error("加载用户失败:", error);
} finally {
setLoading(false);
}
};

return (
<div>
<h1>用户列表 ({total})</h1>

{/* 过滤条件 */}
<div className="filters">
<input
type="number"
value={filters.minAge}
onChange={(e) =>
setFilters({ ...filters, minAge: Number(e.target.value) })
}
placeholder="最小年龄"
/>
<input
type="number"
value={filters.maxAge}
onChange={(e) =>
setFilters({ ...filters, maxAge: Number(e.target.value) })
}
placeholder="最大年龄"
/>
<label>
<input
type="checkbox"
checked={filters.vipOnly}
onChange={(e) =>
setFilters({ ...filters, vipOnly: e.target.checked })
}
/>
仅显示 VIP
</label>
</div>

{/* 用户列表 */}
{loading ? (
<div>加载中...</div>
) : (
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>邮箱</th>
<th>VIP</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{user.email}</td>
<td>{user.vip ? "✓" : ""}</td>
</tr>
))}
</tbody>
</table>
)}

{/* 分页 */}
<div className="pagination">
<button
disabled={currentPage === 1}
onClick={() => setCurrentPage(currentPage - 1)}
>
上一页
</button>
<span>{currentPage}</span>
<button
disabled={currentPage * 20 >= total}
onClick={() => setCurrentPage(currentPage + 1)}
>
下一页
</button>
</div>
</div>
);
}

⚠️ 注意事项

1. 操作符大小写

所有操作符都必须以小写的 $ 开头,大小写敏感:

// ✅ 正确
{
age: {
$eq: 18;
}
}

// ❌ 错误
{
age: {
$EQ: 18;
}
} // 大写不被识别
{
age: {
eq: 18;
}
} // 缺少 $

2. 条件类型

确保条件值的类型与字段类型匹配:

// ✅ 正确 - 数字字段用数字值
{
age: {
$gte: 18;
}
}

// ❌ 错误 - 数字字段用字符串值
{
age: {
$gte: "18";
}
}

// ✅ 正确 - 日期字段用 ISO 字符串
{
createTime: {
$gte: "2025-01-01T00:00:00.000Z";
}
}

3. 性能优化

  • 使用 select 减少返回字段
  • 合理设置 pageSize,避免一次返回过多数据
  • 为常用查询字段添加索引(需联系平台管理员)

📚 相关文档


有问题?查看 故障排查文档 或联系技术支持。