$concat 不能直接生成唯一编码,因其仅拼接字符串、不查重不校验;需结合去重逻辑(如$group计数)或哈希($md5/$sha256)并确保字段类型一致、添加分隔符,且唯一性依赖上游数据质量与外部协调机制。

直接说结论:用 $concat 拼接字段最常用,但“唯一业务编码”不能只靠拼接——必须结合去重逻辑或校验机制,否则 $concat 本身不保证唯一性。
为什么 $concat 不能直接生成唯一编码?
$concat 只是字符串拼接函数,输入相同就输出相同,它不查重、不递增、不校验冲突。常见错误是写成:
{ $project: { bizCode: { $concat: ["$prefix", "$orderNo", "$timestamp"] } } }
结果发现两个不同文档拼出一样的 bizCode,尤其当 $orderNo 是字符串且含前导零、$timestamp 精度只到秒时,极易重复。
- 字段类型不一致会导致隐式转换失败(比如
$concat遇到null直接报错,需先用$ifNull处理) - 时间戳若用
$toDate或$dateToString格式不对,可能丢失毫秒级差异 - 前缀若来自
$lookup结果,而结果为空数组,$concat会收到undefined,触发异常
真正能支撑“唯一性”的组合方案
唯一编码 = 可读性 + 冲突规避。推荐在聚合中分两步走:
- 先用
$concat构建基础编码(带业务语义,如"ORD-20261020-001") - 再用
$group+$sum或$count检查该编码是否已存在;若存在,追加序列号或哈希后缀
例如,在插入前做预检:
[<br> { $project: { baseCode: { $concat: ["ORD-", { $dateToString: { format: "%Y%m%d", date: "$createdAt" } }, "-", { $toString: "$seq" } ] } } },<br> { $group: { _id: "$baseCode", count: { $sum: 1 } } },<br> { $project: { bizCode: { $cond: [ { $eq: ["$count", 1] }, "$_id", { $concat: ["$_id", "-", { $toString: "$count" }] } ] } } }<br>]
注意:$seq 应来自应用层分配或原子计数器集合,聚合管道内无法安全生成自增序号。
替代方案:用 $md5 或 $sha256 生成确定性哈希码
当业务不要求可读、只要求唯一和确定性时,哈希更可靠:
-
$md5输入必须是字符串,非字符串字段得先转:{ $toString: "$_id" }、{ $dateToString: { ... } } - 多个字段拼接前建议加分隔符,避免
"ab"+"c"和"a"+"bc"哈希相同 -
$sha256在 MongoDB 4.4+ 支持,比$md5更抗碰撞,但输出是十六进制字符串,长度固定64位
示例:
{ $project: { bizCode: { $md5: { $concat: ["$prefix", "|", "$orderId", "|", { $dateToString: { format: "%Y-%m-%d %H:%M:%S.%L", date: "$createdAt" } }] } } } }
真正容易被忽略的点:唯一性不是聚合阶段能独立解决的问题。它依赖上游数据质量、字段完整性、以及是否引入外部协调(如计数器集合或应用层锁)。聚合管道可以构造编码、校验冲突、甚至回退重试,但它不提供原子写入保障——要落地唯一编码,最终还得靠 $merge 或应用层幂等控制。











