96444d67fa
GET /api/v1/compare/records 新增 ordered / keyword 两个查询参数,过滤全部下推到 SQL。 不能分页之后再由客户端 filter —— 一页里可能一条都不命中,列表看着就是空的, 得翻很多页才蹦出一条。 顺带修掉这条链路上几处随数据量线性变慢的地方: - 列表查询 defer raw_payload / llm_calls / llm_price_snapshot 三个重型 JSON 列。 出参 ComparisonRecordOut 根本不读,却是每页几百 KB~几 MB 的白读 + 白反序列化, 是「比价记录/全部记录」页慢的主要来源;详情接口不 defer,raw_payload 照常返回。 - 「已下单」标记改为只按本页店名(≤ limit 条)反查 savings,不再把该用户全部下单 店名捞进内存跟 50 条记录取交集。 - 新增 (user_id, created_at, id) 复合索引:反向扫恰好等于列表的 ORDER BY created_at DESC, id DESC,PG 免排序直接取前 n 条。 迁移走 CREATE INDEX CONCURRENTLY,不阻塞线上 harvest 写入。 - keyword 转义 LIKE 通配符后再匹配,避免搜一个「%」把整表拉回来。 - nginx 对 application/json 开 gzip:此前 gzip off + gzip_types 只含 text/html + gzip_proxied off 三个默认值凑一起,等于所有接口都在裸奔;记录列表这种 字段名和中文店名高度重复的 JSON 压缩比稳定 8~10 倍。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
3.2 KiB
Markdown
57 lines
3.2 KiB
Markdown
# GET /api/v1/compare/records — 比价记录列表(游标分页)
|
||
|
||
> 所属:比价记录组(前缀 `/api/v1/compare`) | 鉴权:Bearer | [← 返回 API 索引](../README.md)
|
||
|
||
「我的比价记录」列表页数据源。按 `id` 倒序(最新在前)。
|
||
|
||
## 入参(query)
|
||
|
||
| 字段 | 类型 | 必填 | 默认 | 说明 |
|
||
|---|---|---|---|---|
|
||
| `limit` | int | ❌ | 20 | 1–100 |
|
||
| `cursor` | int | ❌ | null | 上一页末条 `id`,首页不传 |
|
||
| `ordered` | bool | ❌ | null | `true`=只出「已下单」(店名命中本人真实下单)的记录;不传=不筛 |
|
||
| `keyword` | string | ❌ | null | 按店名 / 菜名模糊搜索,忽略大小写,≤64 字符;纯空白等同不传 |
|
||
| `include_trace` | bool | ❌ | false | 客户端开了本机 agent 调试模式时带 `true`,放行**本人**记录的 `trace_url` |
|
||
|
||
`ordered` / `keyword` 都在服务端过滤后再分页,客户端不要拿一页结果自己 filter ——
|
||
分页之后一页里可能一条都不命中,列表会看着像空的。
|
||
|
||
## 出参
|
||
响应 `200`:`{ items: ComparisonRecordOut[], next_cursor: int|null }`(分页见 [索引#游标分页约定](./README.md#游标分页约定))
|
||
|
||
**ComparisonRecordOut**(列表项,不含 `raw_payload`,减小 payload)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `id` | int | 记录 id(也是游标) |
|
||
| `business_type` | string | `food` / `ecom` / `coupon` |
|
||
| `trace_id` | string | pricebot trace_id |
|
||
| `source_platform_id` | string \| null | 源平台代号 |
|
||
| `source_platform_name` | string \| null | 源平台中文名 |
|
||
| `source_package` | string \| null | 源平台包名 |
|
||
| `source_price_cents` | int \| null | 源平台到手价(分) |
|
||
| `best_platform_id` | string \| null | 最优平台代号 |
|
||
| `best_platform_name` | string \| null | 最优平台中文名 |
|
||
| `best_price_cents` | int \| null | 最优价(分) |
|
||
| `saved_amount_cents` | int \| null | 省下(分,可 0/负) |
|
||
| `is_source_best` | bool \| null | 源平台是否最便宜(= 没省到) |
|
||
| `store_name` | string \| null | 店铺名 |
|
||
| `total_dish_count` | int \| null | 菜品总数 |
|
||
| `skipped_dish_count` | int \| null | 跳过菜品数 |
|
||
| `status` | string | `success` / `failed` |
|
||
| `information` | string \| null | done 帧文案。成功:"在美团找到同店,到手价 ¥X…";失败:具体原因(如"美团、京东外卖均未找到该商品"),前端在 `status=failed` 时当原因展示 |
|
||
| `items` | object[] | 下单菜品 `{name, qty, specs?}` |
|
||
| `comparison_results` | object[] | 逐平台对比(price 单位元,已按 rank 升序) |
|
||
| `skipped_dish_names` | string[] | 被跳过的菜名 |
|
||
| `ordered` | bool | 「已下单」店级标记:店名命中本人 `source='compare'` 的下单记录即 `true`。**瞬态字段,不在表里**,每次查询现算 |
|
||
| `ad_coins_earned` | int | 本次比价看信息流广告实发的金币(按 `trace_id` 聚合)。同为瞬态字段 |
|
||
| `trace_url` | string \| null | pricebot 调试链接。未开 `debug_trace_enabled` 且未带 `include_trace=true` 时为 `null` |
|
||
| `created_at` | datetime | 时间 |
|
||
|
||
## 错误
|
||
- `401` 未鉴权
|
||
|
||
## 说明
|
||
只返回当前登录用户自己的记录。需要单条全量(含 `raw_payload`)走 [详情接口](./compare-record-detail.md)。
|