经纬志
首页 / 实战手册 / 样式与渲染

filter 里数字和字符串比较,条件永远是 false

先看结论

明明有 40 个区县人口超过一万,图层上一个都没画出来,也没有报错。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

图层 filter 写成:

filter: ['>=', ['get', 'pop'], 10000]

数据里 pop 是字符串(GeoJSON 属性来自 CSV,全部带引号), 结果 queryRenderedFeatures 返回 0 条, 控制台没有类型错误,只有图层 visibility 正常、颜色正常,就是不显示。

原因

Mapbox 样式的表达式系统是强类型的,不做隐式转换。 ['get','pop'] 返回字符串 "12000", 与数字 10000 比较时,类型不匹配, 比较结果为 false,且不会抛错。

类似地,filter: ['==', ['get','level'], 2] 在 level 为 "2" 时同样恒为 false。 这类问题最难查,因为没有错误信息,只有「没画出来」。

属性值比较结果
"12000">= 10000false
12000>= 10000true
"2"== 2false
"2"== "2"true

排查过程

  1. 取一条要素,打印 typeof f.properties.pop,确认是字符串还是数字。
  2. 把 filter 去掉,看要素是否正常显示,确认是过滤而非样式问题。
  3. 用 ['to-number', ['get','pop']] 包一层,若恢复正常即可定位。
  4. 检查数据源:CSV 转 GeoJSON 时属性常全为字符串,需要显式转换。
const f = map.querySourceFeatures('districts')[0];
console.log(f.properties.pop, typeof f.properties.pop);
// "12000" string

// 去掉 filter 验证
map.setFilter('districts', null);   // 要素出现 -> 过滤条件有问题

解决方案

比较前显式转换,或在数据入库时就转成数字。

map.addLayer({
  id: 'districts',
  type: 'fill',
  source: 'districts',
  filter: ['>=', ['to-number', ['get', 'pop']], 10000],
  paint: { 'fill-color': '#1a6fd4', 'fill-opacity': 0.6 }
});

// 字符串比较则统一加引号
map.setFilter('districts', ['==', ['get', 'level'], '2']);

// 需要排除无法解析的情况
map.setFilter('districts', [
  'all',
  ['has', 'pop'],
  ['>=', ['to-number', ['get', 'pop'], 0], 10000]
]);

数据侧也应该修:GDAL 导出时用 -fieldTypeString 之外的默认类型, 或写一个小脚本把所有数值型字段转成 number。

fc.features.forEach(f => {
  ['pop', 'area'].forEach(k => {
    if (k in f.properties && typeof f.properties[k] === 'string') {
      const n = Number(f.properties[k]);
      if (!Number.isNaN(n)) f.properties[k] = n;
    }
  });
});

验证

queryRenderedFeatures 返回的记录数应等于数据中满足条件的数量(本例约 40 条), 且每条 properties.pop 为 number 类型。

const r = map.queryRenderedFeatures({ layers: ['districts'] });
console.assert(r.length === 40, '过滤结果数量不符:' + r.length);
console.assert(typeof r[0].properties.pop === 'number', '属性仍为字符串');

适用版本

库版本说明
Mapbox GL JS2.15 / 3.x表达式强类型,无隐式转换
MapLibre GL JS3.x / 4.x行为一致
Mapbox 样式规范v8to-number 可带兜底默认值
引用本文

经纬志(2026)。《filter 里数字和字符串比较,条件永远是 false》。https://www.jingweizhi.com/cookbook/filter-number-vs-string.html(访问日期 2026-11-03)。