设计一个筛选函数仅复制“type:order”且金额大于 1000 的文档,并给出 JSON 示例。
解读
国内一线互联网公司在面试 CouchDB 岗位时,常把“复制过滤器”作为区分“只会 CRUD”与“能驾驭分布式”的分水岭。
面试官真正想听的是:
- 你能否用 Erlang 格式 写出 filter 函数 并正确注册到
_design/; - 你能否解释该函数在 多主复制 链路中的执行位置与性能影响;
- 你能否给出 最小但可验证 的 JSON 样例,证明金额字段是 数值型 而非字符串,避免踩“字符串比较”坑。
一句话:函数必须返回布尔值,字段类型必须对,复制链路必须知道跑在源端还是目标端。
知识点
- 设计文档(_design):过滤器必须写在
_design/filters路径下,函数名即为过滤器名。 - filter 函数签名:
function(doc, req) -> boolean;req可携带用户参数,但本题无需。 - 字段类型:金额必须
typeof doc.amount === 'number',国内支付系统金额统一用 分或元 存整数或浮点,需与面试官对齐。 - 复制 API:
POST /_replicate或PUT /_replicator/{docId},JSON 体内加"filter": "orders/high_value"。 - 性能:过滤器在 源端 执行,每文档一次函数调用;国内大数据场景下,百万级文档 需评估 Erlang 与 JavaScript 切换开销,必要时改写成 Erlang 原生 过滤器。
答案
- 设计文档(存于源库)
{
"_id": "_design/orders",
"filters": {
"high_value": "function(doc, req) { return doc.type === 'order' && typeof doc.amount === 'number' && doc.amount > 1000; }"
}
}
- 触发复制(国内常用
_replicator数据库,支持断点续传)
PUT /_replicator/order_sync HTTP/1.1
Content-Type: application/json
{
"_id": "order_sync",
"source": "http://user:pass@source.corp.k8s.local:5984/shop",
"target": "http://user:pass@target.corp.k8s.local:5984/shop",
"filter": "orders/high_value",
"continuous": true,
"worker_processes": 4
}
- 符合规则的示例文档
{
"_id": "order:2025062500001",
"type": "order",
"amount": 1688.00,
"buyer": "13800138000",
"items": [{ "sku": "MI13-256", "qty": 1 }]
}
- 不符合规则的示例文档
{
"_id": "order:2025062500002",
"type": "order",
"amount": "500", // 字符串,被过滤
"buyer": "13900139000"
}
拓展思考
- 灰度放量:国内金融场景常要求“金额>1000 且用户等级>黄金”才复制,可把
req.query.level透传进过滤器,实现 同函数多策略。 - 字段升级:若后续金额拆分为
amount/cent,过滤器需兼容旧字段,用doc.amount > 1000 || (doc.cent && doc.cent > 100000)做 平滑迁移。 - 性能调优:当源库文档过亿,过滤器会成为瓶颈;可前置 ** Mango 索引** 做预过滤,或在 Kafka 层 先裁剪数据,再喂给 CouchDB,实现 批流一体。