开发 MongoDB优惠活动规则配置怎么存 表达式与条件树内嵌|Duuu笔记
前端进阶技巧:本文深入解析
嵌套文档更合理:单活动专属规则直接存 promotions 文档的 rules 字段;跨活动共享规则则拆至 promo_rules 集合,用 rule_id 引用并加 version 灰度控制。
优惠规则用嵌套文档还是单独集合
直接存嵌套文档更合理,尤其当规则和商品/活动生命周期强绑定时。MongoDB 的
document
天然支持树形结构,把条件树塞进
conditions
字段里,查活动时一并取出,避免多次查询或 $lookup 关联。
但要注意:如果同一套规则被上百个活动复用,或者规则本身频繁更新、需独立审计,那就该拆到
promo_rules
集合里,用
rule_id
引用——否则每次改规则都要批量更新所有活动文档,容易写冲突或漏更新。
单活动专属规则 → 嵌套在
promotions
文档的
rules
字段里
跨活动共享规则 → 单独集合 + ObjectId 引用,加
version
字段做灰度控制
规则字段名别叫
expression
(易误解为字符串脚本),用
condition_tree
更准确
条件树结构怎么设计才方便执行和调试
别用纯字符串存表达式(比如
"price > 100 && user.level >= 2"
),执行靠 JS
eval
或服务端解析,既慢又不安全。应该用可序列化的结构描述逻辑关系:
{
"type": "AND",
"children": [
{
"type": "GT",
"field": "order_amount",
"value": 100
},
{
"type": "IN",
"field": "user.tags",
"value": ["vip", "gold"]
}
]
}
这种结构能直接映射成后端 if 判断链,也方便前端可视化编辑器渲染节点。注意几个坑:
field
路径要统一用点号分隔(如
"user.profile.age"
),避免数组下标(
"items.0.name"
)导致匹配歧义
叶子节点的
value
类型必须明确:数字就存 Number,字符串带引号,布尔值用
true
/
false
,别混成字符串
"true"
如果支持“当前时间比较”,字段名别硬写
"now"
,用占位符
"$NOW"
,执行时再替换,防止序列化时出错
表达式里引用动态上下文字段怎么安全取值
规则执行时需要读订单、用户、商品等上下文数据,但不能让表达式任意访问对象属性(比如
user.__proto__.constructor.eval(...)
)。推荐两种方式:
白瓜AI
白瓜AI,一个免费图文AI创作工具,支持 AI 仿写,图文生成,敏感词检测,图片去水印等等。
下载
白名单字段投影:执行前只把允许访问的字段扁平化注入一个干净对象,如
{ order_amount: 199, user_level: 3, sku_category: "electronics" }
,表达式只能读这些 key
沙箱函数封装:用
get("user.level")
或
ctx("order.items.0.price")
这类受限访问函数,内部做路径校验和类型兜底,不暴露原始对象
绝对不要在 MongoDB 查询里用
$where
执行用户传入的 JS 表达式——它会全库扫描、无法索引,且有执行任意代码风险
性能和索引怎么配合条件树生效
条件树本身没法建索引,但高频过滤字段可以单独拎出来冗余存储。比如一个满减规则常看
order_amount
和
user.tier
,就在活动文档里加两个字段:
min_order_amount: 100
、
required_user_tier: "gold"
,然后对它们建复合索引:
db.promotions.createIndex({ "min_order_amount": 1, "required_user_tier": 1, "status": 1 })
这样查“当前可用的满减活动”时先走索引快速筛选,再对结果集逐个执行完整条件树判断。容易忽略的是:如果条件树里有
IN
或
REGEX
这类低效操作,得在应用层加缓存或预计算,MongoDB 本身扛不住实时遍历。
树越深、节点越多,执行耗时越不可控;线上建议限制最大深度为 4,单节点条件数不超过 8,超出就报错提示运营配置异常。
