使用mgo操作MongoDB时,不同参数类型查询结果差异的原因
问题原因分析:mgo中interface{}与int64作为_id查询的差异
这个问题的核心在于mgo(gopkg.in/mgo.v2)对interface{}类型值的BSON序列化逻辑,和明确的int64类型存在关键差异,导致生成的查询条件无法匹配MongoDB中存储的文档。
具体差异拆解
明确int64类型的情况
当你使用int64类型的变量作为_id参数时,mgo会直接将其序列化为BSON规范中的NumberLong(对应int64)类型。如果你的MongoDB文档中_id正是以NumberLong存储的,那么类型完全匹配,查询自然能命中目标文档。interface{}类型的情况
你第一个例子中,var id interface{}; id = 249678041972736这段代码,在Go语言中,无后缀的整数字面量默认类型是int(64位系统中int长度等价于int64,但类型标识仍是int)。当这个int类型的值被存入interface{}后,mgo在序列化BSON时,会按照int类型的规则处理:- mgo会优先尝试将
int类型序列化为BSON的NumberInt(int32)类型,而你的数值249678041972736远超过int32的最大值(2147483647),会导致数值截断或类型不匹配。最终生成的查询条件和MongoDB中存储的NumberLong类型_id无法匹配,因此返回“not found”。
- mgo会优先尝试将
解决办法
针对这个问题,你可以选择以下几种方案:
明确转换类型:在将数值赋值给
interface{}变量时,强制转换为int64,比如:var id interface{} id = int64(249678041972736) // 明确转为int64类型这样
interface{}的动态类型是int64,mgo会正确序列化为NumberLong,查询就能成功。固定参数类型:像你第二个例子那样,将
GetUser函数的参数类型固定为int64,从根源避免interface{}带来的类型不确定性。类型断言处理:如果需要函数支持多种类型的
_id,可以在函数内部通过类型断言将参数转换为正确的类型后再构建查询:import "fmt" import "errors" func GetUser(id interface{}) (*User, error) { session := MongoDB() defer session.Close() var m *User var queryId interface{} switch v := id.(type) { case int: queryId = int64(v) // 将int转为int64 case int64: queryId = v case string: queryId = v // 兼容字符串类型的_id default: return nil, fmt.Errorf("unsupported id type: %T", v) } err := session.DB.C("user").Find(bson.M{"_id": queryId}).One(&m) if err != nil { return nil, err } return m, nil }
内容的提问来源于stack exchange,提问作者Holdno
相关产品推荐
相关产品推荐

