因为 filename 是完整路径字符串,MongoDB 原生无 split 函数,直接 $group 只能按全名分组;需用 $regexFind 提取最后一个点后的后缀(如 ".pdf"),再 $group 统计。

为什么 filename 字段不能直接按后缀分组?
GridFS 的 files 集合中,filename 是完整路径或带扩展名的字符串(如 "report.pdf" 或 "images/photo_2024.jpg"),MongoDB 原生不提供 split 或 lastIndexOf 类函数。直接用 $group 对 filename 分组只能得到全名,不是后缀。
用 $regexFind 提取后缀再分组
从 MongoDB 4.2 起支持 $regexFind,可安全提取最后一个点后的部分。注意必须加 name: "ext" 别名才能在后续阶段引用:
[
{
$addFields: {
ext: {
$regexFind: {
input: "$filename",
regex: "\.[^\.]+$",
options: "i"
}
}
}
},
{
$addFields: {
extension: { $ifNull: ["$ext.match", ""] }
}
},
{
$group: {
_id: "$extension",
count: { $sum: 1 }
}
}
]
关键点:
-
\.[^\.]+$匹配最后一个点及之后所有非点字符(避免误抓中间点,如"data.tar.gz"→".gz") -
options: "i"让大小写不敏感(.PDF和.pdf归为一类) -
$ifNull处理无后缀文件(如"README"),避免null进入分组
如果用旧版 MongoDB(
只能靠 $substrBytes + $strLenBytes 手动倒序截取,但不可靠:无法定位最后一个点位置,对多字节字符(如中文文件名)易出错。更稳妥的做法是:
以 CLI 为先的表单构建器,采用 BYOK 理念。通过JSON Schema 生成美观的 HTML 表单,使用您自己的 SMTP 服务器处理提交,存储响应...
- 应用层统一保存后缀到自定义字段(如
metadata.ext),再建索引 - 或用
$function(MongoDB 4.4+)写 JS 逻辑(不推荐用于生产聚合,性能差且禁用在分片集群) - 绕过 GridFS,改用普通集合存文件元信息,把后缀作为独立字段
统计结果里空字符串 "" 是什么?
它代表没有后缀的文件,比如 "Dockerfile"、"LICENSE" 或误传的 "temp"。这类文件常被忽略,但实际可能占不小比例。如果业务要求强制后缀,可在上传时校验并拒绝无扩展名文件,比事后清洗更可靠。
真正麻烦的是混合命名风格:有人传 "avatar.png?ver=2",有人传 "script.min.js" —— 正则得兼顾 query string 和多重点,这时单靠聚合难覆盖全场景。










