必须用Select()(mgo)或SetProjection()(官方驱动)单独设置排除规则,因Find()仅接受查询条件参数,投影若错误传入会导致解析异常、返回空结果;排除字段需用{"field": 0}语法,且_id须显式声明"_id": 0。

直接在 find() 里传投影参数会查不到数据,必须用 Select()(mgo)或 SetProjection()(官方驱动)单独设置排除规则。
Go 中用 mgo 驱动排除字段:不能把投影塞进 Find()
很多人写成 col.Find(bson.M{}, bson.M{"password": 0}) 或 col.Find([]bson.M{{}, {"password": 0}}),这会导致 MongoDB 解析出错,实际执行的是非法查询,结果为空。
-
Find()只接受一个参数:查询条件(filter),比如bson.M{"status": "active"}或nil - 字段排除属于投影(projection),必须走链式调用:
.Select(bson.M{"password": 0, "token": 0}) -
_id默认总返回,要排除必须显式写"_id": 0 -
Select()必须在Find()之后、All()/One()之前调用
Go 官方驱动(mongo-go-driver)怎么排除字段
官方驱动不支持链式 Select(),得用 options.FindOptions 构造投影选项:
opt := options.Find().SetProjection(bson.M{"password": 0, "email": 0})
cur, err := col.Find(ctx, bson.M{"deleted": false}, opt)
注意两点:
-
SetProjection()的参数和 mgo 的Select()一样,用{"field": 0}表示排除 - 不能混用包含(
1)和排除(0),除非_id单独设为1;比如{"name": 1, "password": 0}是非法的
为什么 "password": 0 能排除字段,而 "password": false 不行
MongoDB 投影协议只认整数 0 和 1,false 会被当作布尔值忽略,等价于没写这个字段,结果就是该字段照常返回。
- 写
"password": 0→ 明确排除 - 写
"password": false→ 投影中无此键,不生效 - 写
"password": bson.M{"$eq": 0}→ 类型错误,MongoDB 直接报错
字段排除不是“隐藏”,而是服务端裁剪
排除字段发生在数据库返回前,网络传输量减少,客户端也收不到原始值——这点和 ORM 层的 [BsonIgnore] 或序列化过滤有本质区别。
-
[BsonIgnore]是 Go struct tag,只影响 Go 对象与 BSON 的编解码,不影响查询本身 - 真正防止敏感字段泄露,必须靠服务端投影,否则即使结构体没字段,wire 上仍可能暴露
- 聚合管道里也能用
$project排除,但开销比普通find大,非必要不用
最容易被忽略的是:_id 必须显式排除,而且一旦用了 0,所有其他字段默认包含——别指望它像 SQL 的 SELECT * 那样自动推导。


















