设计一个筛选函数仅复制“type:order”且金额大于 1000 的文档,并给出 JSON 示例。

解读

国内一线互联网公司在面试 CouchDB 岗位时,常把“复制过滤器”作为区分“只会 CRUD”与“能驾驭分布式”的分水岭。
面试官真正想听的是:

  1. 你能否用 Erlang 格式 写出 filter 函数 并正确注册到 _design/
  2. 你能否解释该函数在 多主复制 链路中的执行位置与性能影响;
  3. 你能否给出 最小但可验证 的 JSON 样例,证明金额字段是 数值型 而非字符串,避免踩“字符串比较”坑。

一句话:函数必须返回布尔值,字段类型必须对,复制链路必须知道跑在源端还是目标端

知识点

  • 设计文档(_design):过滤器必须写在 _design/filters 路径下,函数名即为过滤器名。
  • filter 函数签名function(doc, req) -> booleanreq 可携带用户参数,但本题无需。
  • 字段类型:金额必须 typeof doc.amount === 'number',国内支付系统金额统一用 分或元 存整数或浮点,需与面试官对齐。
  • 复制 APIPOST /_replicatePUT /_replicator/{docId},JSON 体内加 "filter": "orders/high_value"
  • 性能:过滤器在 源端 执行,每文档一次函数调用;国内大数据场景下,百万级文档 需评估 Erlang 与 JavaScript 切换开销,必要时改写成 Erlang 原生 过滤器。

答案

  1. 设计文档(存于源库)
{
  "_id": "_design/orders",
  "filters": {
    "high_value": "function(doc, req) { return doc.type === 'order' && typeof doc.amount === 'number' && doc.amount > 1000; }"
  }
}
  1. 触发复制(国内常用 _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
}
  1. 符合规则的示例文档
{
  "_id": "order:2025062500001",
  "type": "order",
  "amount": 1688.00,
  "buyer": "13800138000",
  "items": [{ "sku": "MI13-256", "qty": 1 }]
}
  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,实现 批流一体