Records API
PocketBase Records API 提供标准的 REST 接口来操作集合中的记录。所有操作都支持完整的 CRUD(创建、读取、更新、删除)以及高级查询功能。
/api/collections/{collection}/recordsGET /api/collections/posts/records?page=1&perPage=20响应示例:
{ "page": 1, "perPage": 20, "totalItems": 150, "totalPages": 8, "items": [ { "id": "rxk2z3j1w34o8vj", "collectionId": "pbc_1234567890", "collectionName": "posts", "title": "Hello PocketBase", "content": "...", "created": "2024-01-15 10:30:00.000Z", "updated": "2024-01-15 10:30:00.000Z" } ]}简化列表(不分页)
Section titled “简化列表(不分页)”GET /api/collections/posts/records?skipTotal=1设置 skipTotal=1 可以跳过 totalItems 计数,提高大数据集查询性能。
过滤(Filter)
Section titled “过滤(Filter)”GET /api/collections/posts/records?filter=status='published'| 运算符 | 说明 | 示例 |
|---|---|---|
= | 等于 | filter=status='active' |
!= | 不等于 | filter=status!='draft' |
> | 大于 | filter=views>100 |
>= | 大于等于 | filter=views>=100 |
< | 小于 | filter=price<50 |
<= | 小于等于 | filter=price<=50 |
~ | 包含(字符串) | filter=title~'pocketbase' |
!~ | 不包含 | filter=title!~'test' |
# AND(默认空格分隔)GET /api/collections/posts/records?filter=status='published' && featured=true
# ORGET /api/collections/posts/records?filter=status='draft' || status='archived'
# 分组GET /api/collections/posts/records?filter=(status='published' && featured=true) || authorId='abc'# 字段为空filter=publishedAt=null
# 字段不为空filter=publishedAt!=null数组字段过滤
Section titled “数组字段过滤”# 包含某个标签filter=tags~'javascript'
# 多选字段包含某值filter=categories~'tech'常见过滤模式
Section titled “常见过滤模式”# 按日期范围查询filter=created>='2024-01-01' && created<='2024-12-31'
# 按用户过滤filter=authorId=@request.auth.id
# 搜索多个字段filter=title~'search' || content~'search'
# 组合多个条件filter=status='published' && publishedAt<='2024-01-15' && featured=true排序(Sort)
Section titled “排序(Sort)”# 升序GET /api/collections/posts/records?sort=created
# 降序(减号前缀)GET /api/collections/posts/records?sort=-created# 先按状态降序,再按创建时间降序GET /api/collections/posts/records?sort=-status,-created
# 复杂排序:featured 优先,然后按时间GET /api/collections/posts/records?sort=-featured,-created支持随机排序
Section titled “支持随机排序”GET /api/collections/posts/records?sort=@random选择特定字段
Section titled “选择特定字段”# 只返回 id 和 titleGET /api/collections/posts/records?fields=id,title,created
# 嵌套选择(relation 字段)GET /api/collections/posts/records?fields=id,title,author.name# 排除 content 字段GET /api/collections/posts/records?fields=-content关联查询(Relations)
Section titled “关联查询(Relations)”扩展关联字段
Section titled “扩展关联字段”# 扩展单个 relationGET /api/collections/posts/records?expand=author
# 扩展多个 relationGET /api/collections/posts/records?expand=author,category
# 嵌套扩展GET /api/collections/posts/records?expand=author.avatar{ "items": [ { "id": "rxk2z3j1w34o8vj", "title": "Post Title", "author": "author_id_here", "expand": { "author": { "id": "author_id_here", "name": "John Doe", "email": "john@example.com" } } } ]}CRUD 操作
Section titled “CRUD 操作”POST /api/collections/posts/recordsContent-Type: application/json
{ "title": "My First Post", "content": "This is the content...", "status": "draft", "tags": ["javascript", "pocketbase"]}使用 FormData(文件上传):
POST /api/collections/posts/recordsContent-Type: multipart/form-data
------BoundaryContent-Disposition: form-data; name="title"
My First Post------BoundaryContent-Disposition: form-data; name="cover"; filename="image.jpg"Content-Type: image/jpeg
(binary data)------Boundary--读取单条记录
Section titled “读取单条记录”GET /api/collections/posts/records/{id}PATCH /api/collections/posts/records/{id}Content-Type: application/json
{ "title": "Updated Title", "status": "published"}DELETE /api/collections/posts/records/{id}# 需要通过 filter 筛选DELETE /api/collections/posts/records?filter=status='spam'注意: 批量操作受集合规则限制,确保规则允许此类操作。
SDK 使用示例
Section titled “SDK 使用示例”JavaScript SDK
Section titled “JavaScript SDK”import PocketBase from "pocketbase";
const pb = new PocketBase("http://127.0.0.1:8090");
// 列表查询(带过滤和排序)const records = await pb.collection("posts").getList(1, 20, { filter: 'status="published" && featured=true', sort: "-created", expand: "author,category",});
// 简化列表const allRecords = await pb.collection("posts").getList(1, 50, { skipTotal: true,});
// 获取单条记录const record = await pb.collection("posts").getOne("record_id");
// 创建记录const created = await pb.collection("posts").create({ title: "New Post", content: "Content here...", status: "draft",});
// 更新记录const updated = await pb.collection("posts").update("record_id", { title: "Updated Title",});
// 删除记录await pb.collection("posts").delete("record_id");
// 使用 FormData 创建(带文件)const formData = new FormData();formData.append("title", "Post with Image");formData.append("cover", fileInput.files[0]);const withFile = await pb.collection("posts").create(formData);Go SDK
Section titled “Go SDK”import "github.com/pocketbase/pocketbase/daos"
// 列表查询records, err := dao.FindRecordsByFilter( "posts", "status='published' && featured=true", "-created", 20, // limit 0, // offset)
// 获取单条record, err := dao.FindRecordById("posts", "record_id")
// 创建record := &models.Record{}record.SetData(map[string]any{ "title": "New Post", "content": "Content...",})err := dao.CreateRecord(record)
// 更新record.SetData(map[string]any{ "title": "Updated Title",})err := dao.SaveRecord(record)
// 删除err := dao.DeleteRecord(record)性能优化建议
Section titled “性能优化建议”1. 合理使用索引
Section titled “1. 合理使用索引”为高频过滤和排序字段创建索引:
- 状态字段(
status) - 外键字段(
authorId、categoryId) - 日期字段(
created、publishedAt) - 搜索字段(
slug)
2. 减少返回数据
Section titled “2. 减少返回数据”使用 fields 参数只获取需要的字段:
GET /api/collections/posts/records?fields=id,title,slug3. 使用 skipTotal
Section titled “3. 使用 skipTotal”对于无需总数的场景,跳过计数:
GET /api/collections/posts/records?skipTotal=14. 限制深度
Section titled “4. 限制深度”避免过深的 expand 嵌套,考虑多次查询或使用 GraphQL 风格的自定义接口。
5. 缓存策略
Section titled “5. 缓存策略”- 对于不常变化的数据,客户端缓存结果
- 使用
ETag或Last-Modified头实现条件请求 - 考虑使用 PocketBase 的缓存中间件
Q: 如何实现全文搜索?
Section titled “Q: 如何实现全文搜索?”PocketBase 使用 SQLite,默认支持简单的 LIKE 查询:
filter=title~'keyword' || content~'keyword'对于复杂全文搜索,可以考虑:
- 使用 FTS5 扩展(需要自定义 PocketBase)
- 集成专业搜索引擎(如 Meilisearch)
- 使用外部搜索服务(如 Algolia)
Q: 如何处理分页中的数据变化?
Section titled “Q: 如何处理分页中的数据变化?”// 方案 1: 使用游标分页(基于时间戳)const records = await pb.collection("posts").getList(1, 50, { filter: `created<'${lastTimestamp}'`, sort: "-created",});
// 方案 2: 客户端去重const ids = new Set();const uniqueRecords = records.items.filter((r) => { if (ids.has(r.id)) return false; ids.add(r.id); return true;});Q: 如何实现”加载更多”?
Section titled “Q: 如何实现”加载更多”?”let page = 1;const perPage = 20;let hasMore = true;
async function loadMore() { if (!hasMore) return;
const result = await pb.collection("posts").getList(page, perPage);
result.items.forEach((item) => appendToList(item));
hasMore = result.items.length === perPage; page++;}Q: relation 字段如何排序?
Section titled “Q: relation 字段如何排序?”# 主记录排序GET /api/collections/posts/records?sort=-created
# 扩展的 relation 排序(需要在查询中处理)# 当前不支持直接在 expand 中排序,建议:# 1. 在数据库层面添加排序字段# 2. 或在前端对 expand 结果排序- 始终验证规则:确保 API 规则与业务需求匹配
- 限制查询深度:避免深层嵌套的 expand 导致性能问题
- 监控查询性能:记录慢查询,优化索引
- 使用批量操作限制:对批量删除/更新添加额外验证