关系
直接了当的说,原生的_id 和 string 二者之间不能直接转换。非原生 _id 则因具体而定。
原因
mongoDB 生成的 _id 是二进制数据;而不是 golang 的 string ;二进制转换成 string,必定输出乱码字符。如果写入DB时 _id 由用户生成,那么mongoDB保持原样写入DB,用户传入的类型是什么,此 _id 将是什么类型。DB不做任何修改。
mongoDB原生的 _id 查询是显示像这样
{ "_id" : ObjectId("5a6ae25f614ca7fb150ac1f6")}
中间显示的字符串是二进制的十六进制表示。同理,当查询时,传入十六进制字符串,要转换成 _id 的格式才能查询到正确结果
>db.col.find({"_id" : ObjectId("5a6ae25f614ca7fb150ac1f6")}) //right
>db.col.find({"_id" : "5a6ae25f614ca7fb150ac1f6"}) //查无此人
采用二进制的原因可能为了最小化存储空间吧。
解决办法
读取
在golang中使用byte数组或者使用bson.ObjectId,像这样
type Info struct {
Id []byte `bson:"_id"`
}
//或者
type Info struct {
Id bson.ObjectId `bson:"_id"`
}
如果使用byte数组,则需要自己转换成十六进制,才是查询时显示的16进制字符串来使用,相比还是建议直接使用 bson.ObjectId,得到的结果就是16进制字符串。
import "encoding/hex"
//func EncodeToString(src []byte) string
id := hex.EncodeToString(info.Id)
还有一种办法就是上面说的自己生成 _id ,这个成本略微大一点,因为它需要一个唯一 id 的生成器。
查询
读取时返回 _id 的16进制字符串,那么反过来查询请求自然也需要转换,golang中如下操作
idList := make([]bson.ObjectId, len(req.Id))
for i, id := range req.Id {
idList[i] = bson.ObjectIdHex(id)
}
sel := bson.M{"_id": bson.M{"$in": idList}}