基本结构定义
type User struct {
ID bson.ObjectId `bson:"_id"` // 通过 bson tag 定义在数据库的字段名
Name string `bson:"name"` // 如果没有 bson tag, 则会使用字段名小写
}
_id 自动生成
type User struct {
ID bson.ObjectId `bson:"_id,omitempty"`
}
如果 ID 字段的 bson 不设置 omitempty, 则创建数据时需要主动赋值. 带上 omitempty, 则会由数据库自动生成一个值. 缺点是使用Insert创建完无法知道ID值.
注1: 仅针对
_id字段会自动赋值. 注2: 如果json/bsontag 之间使用空格分隔, 不可用 Tab 分隔: Cannot retrieve “_id” value using mgo with golang
数组
type User struct {
ID bson.ObjectId `bson:"_id"`
Name string `json:"name"`
Emails []string `json:"emails"`
}
其中Emails是数组:
- 当
Emails == nil时, 写入数据库时会写入空数组[]; - 当数据库中
emails == null时, 读出的Emails == nil, json 序列化救过会是"emails": null;
TODO: 客户端调用API时会期望emails永远是个数组, 所以需要有个方法在反序列化时将 Emails == nil 的场景处理掉.
内嵌结构体
type Admin struct {
User `bson:",inline"`
}
如果不使用 bson:",inline", 最终的数据库会是这样:
{
// 其他字段忽略...
"user": {
"phone": "xxx"
}
}
官方文档: mgo/bson#Marshal
指针 与 选填字段
type Task struct {
ID bson.ObjectId `json:"_id" bson:"_id"`
// 必填字段
CreatorID bson.ObjectId `json:"_creatorId" bson:"_creatorId"`
// 非必填, **为空时数据库存储为 null**
ExecutorID *bson.ObjectId `json:"_executorId" bson:"_executorId"`
// 非必填, **为空时数据库不存储此字段**
AppID bson.ObjectId `json:"_appId,omitempty" bson:"_appId,omitempty"`
}
var id1 = bson.NewObjectId() var id2 bson.ObjectId var id3 *bson.ObjectId = nil var id4 *bson.ObjectId = &id1 var id5 *bson.ObjectId = &id2
| 字段定义 vs 写入行为 | bson.ObjectId | bson.ObjectId + omitempty | *bson.ObjectId | *bson.ObjectId + omitempty |
|---|---|---|---|---|
| id1 | √ | √ | - | - |
| id2 | × | √* | - | - |
| id3 | - | - | √ | √* |
| id4 | - | - | √ | √ |
| id5 | - | - | × | × |
*: 表示写入后无此字段, 区别与写入后值为null