通配符索引仅适用于字段名不可预知的schema-less场景,如爬虫动态字段、命名空间嵌套路径、用户自定义属性等;必须用"field.$**"语法声明路径模式,禁用模糊写法;其性能易受索引膨胀、低选择性及无法投影影响,需结合压测与替代方案谨慎使用。

通配符索引(WildcardIndex)不能加速以 $regex 开头的左模糊匹配(如 ^abc 以外的 .*abc),也不能替代文本索引做全文模糊搜索;它只对明确路径的嵌套字段动态建索引,且仅在查询能命中具体字段路径时才生效。
什么时候该用 WildcardIndex 而不是 text 或普通索引
当你有大量结构不固定、字段名动态生成的嵌套文档(比如用户自定义属性 metadata.tags、metadata.priority、metadata.2024_q3_status),又需要对其中任意一个字段做等值或前缀查询时,WildcardIndex 才真正有用。它不是为 {name: {$regex: ".*liu.*"}} 这类字符串模糊设计的。
- ✅ 适用场景:
db.items.createIndex({"metadata.$**": 1})+ 查询{'metadata.color': 'blue'}或{'metadata.version': {$gte: '2.1'}} - ❌ 不适用:
{name: {$regex: 'liu'}}、{desc: {$regex: '^fast.*'}}、{tags: {$in: ['a', 'b']}}(除非tags是metadata下的子字段且被$**覆盖) - ⚠️ 注意:
$**不展开数组内容——{"metadata.tags.$**": 1}无效,tags: ["x", "y"]中的"x"不会被单独索引
$regex 查询慢?先确认是否真能走索引
MongoDB 的 $regex 只有在满足「前缀固定」且「区分大小写」时,才可能利用普通 B-tree 索引——即形如 ^abc(注意必须带 ^ 锚点),且不能加 i 标志。一旦用了 .*abc 或 /abc/i,就必然全表扫描。
- ✅ 可走索引:
{name: {$regex: "^Alice"}}→ 若有{name: 1}索引 - ❌ 不走索引:
{name: {$regex: "lice$"}}、{name: {$regex: ".*lice.*"}}、{name: {$regex: /alice/i}} - ? 替代方案:把常用模糊模式转成前缀字段预计算,例如加一个
name_prefix_3字段存"Ali",再查{name_prefix_3: "Ali"}
通配符索引的性能代价和限制
WildcardIndex 本质是自动为所有匹配路径创建单字段索引,索引体积和构建耗时随文档嵌套深度与字段数量线性增长。它不压缩、不合并、不可部分禁用。
- ? 索引大小可能远超数据本身——尤其当
metadata下有几十个动态字段时 - ? 写入延迟上升:每次插入/更新命中
$**路径的字段,都要同步更新多个索引条目 - ? 不支持稀疏(
sparse: true)、TTL、部分过滤表达式(partialFilterExpression) - ? 查询必须显式指定字段路径,
{'metadata.$**': 'blue'}不合法,MongoDB 不支持通配符路径查询值
真正提升模糊匹配性能的可行路径
别指望 WildcardIndex 解决字符串模糊问题。要提速,得换思路:
- 用
text索引 +$text查询替代简单关键词模糊,但要求分词语言支持、且不支持正则逻辑 - 对高频模糊字段启用
collation: {locale: "simple", strength: 1}避免大小写/重音干扰,减少索引膨胀 - 把模糊逻辑下沉到应用层:用 Elasticsearch 或 Meilisearch 做前置检索,MongoDB 只存结果 ID
- 如果只是校验“是否包含子串”,考虑用
$indexOfCP+ 覆盖查询(projection里只取必要字段),避免文档反序列化开销
最常被忽略的一点:WildcardIndex 的 include 和 exclude 选项无法用于 $**,你不能说“只索引 metadata 下除 blob 外的所有字段”——要么全索,要么手动列字段建复合索引。











