isayme / blog

https://blog.isayme.org
MIT License
10 stars 2 forks source link

mgo 使用入门及进阶 #15

Open isayme opened 6 years ago

isayme commented 6 years ago

基本结构定义

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/bson tag 之间使用空格分隔, 不可用 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是数组:

  1. Emails == nil 时, 写入数据库时会写入空数组[];
  2. 当数据库中 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

其他资料