在 Go 中从 MySQL 迁移到 Mongo 时处理 NULL
Dealing with NULLs when migrating from MySQL to Mongo in Go
设置
我使用 MySQL 开始了一个项目,因此,我的项目有一些帮助处理空值的帮助程序类型,无论是在 API 上解组传入数据时,还是将数据输入数据库时,然后与之相反,从数据库中提取数据并将所述数据响应到 API.
出于这个问题的目的,我们将处理我拥有的表示字符的结构。
type Character struct {
MongoID primitive.ObjectID `bson:"_id" json:"-"`
ID uint64 `bson:"id" json:"id"`
Name string `bson:"name" json:"name"`
CorporationID uint `bson:"corporation_id" json:"corporation_id"`
AllianceID null.Uint `bson:"alliance_id" json:"alliance_id,omitempty"`
FactionID null.Uint `bson:"faction_id" json:"faction_id,omitempty"`
SecurityStatus float64 `bson:"security_status" json:"security_status"`
NotModifiedCount uint `bson:"not_modified_count" json:"not_modified_count"`
UpdatePriority uint `bson:"update_priority" json:"update_priority"`
Etag null.String `bson:"etag" json:"etag"`
CachedUntil time.Time `bson:"cached_until" json:"cached_until"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}
我想特别关注 null.Uint
类型的 AllianceID 属性,它用以下结构表示:
// Uint is an nullable uint.
type Uint struct {
Uint uint
Valid bool
}
在使用 JSON 和 MySQL 的 API 设置中(即我的设置,但这不是唯一的),这种结构使我能够轻松处理“可为空的值" 而不必处理指针。我一直听说最好避免使用指针,但结构指针除外(切片、结构切片、结构映射等)。如果您有基本类型(int、bool、float 等),请尽量避免使用指向该基本类型的指针。
此类型具有 MarshalJSON
、UnmarshalJSON
、Scan
和 Value
等函数,这些函数中的逻辑利用 Vaild 属性 来确定return 是什么类型的值。这在这个设置下效果非常好。
问题
经过一些研究,我开始意识到 Mongo 比关系数据库更适合我,但是由于 Mongo 文档(无模式)的流动性,我很难理解如何处理可能缺少字段的场景,或者我在 MySQL 中的 属性 通常为 null 的情况,我可以轻松地解组此结构并在逻辑上使用辅助函数, 被处理。此外,当我设置与 Mongo 的连接并从 MySQL 中提取几行并从这些行中创建 Mongo 中的文档时,BSON 层正在编组 Alliance ID 的整个类型和将其粘贴到数据库中。
示例:
"alliance_id" : {
"uint" : NumberLong(99007760),
"valid" : true
},
在 MySQL 中,将调用实现 Valuer 接口的值函数,并且 return 99007760
就是数据库中的值。
另一种情况是 valid 为 false。在 MySQL 中,这意味着空值,当调用 Value 函数时,它将 return nil 并且 mysql 驱动程序将使用 NULL
[=25= 填充字段]
所以我的问题是我该怎么做?我是否需要从头开始并重建我的模型并重做我的应用程序中利用 Valid 属性 和使用 *Pointers
的一些逻辑,或者我可以使用这些帮助程序类型做我想做的事情吗.
我确实想说我已经尝试在bson包上实现Marshaller
和Unmarshaller
接口,文档中的alliane_id仍然设置为json 我上面概述的这种类型的编码版本。我想指出这一点以排除实施这些接口的任何建议。如果我试图实现的目标与 Mongo 的直觉相反,请 link 一些指南可以帮助我实现我正在尝试做的事情。
感谢所有对此提供帮助的人。
像这样处理可选字段的最简单方法是使用指针:
type Character struct {
ID *uint64 `bson:"id,omitempty" json:"id"`
Name string `bson:"name" json:"name"`
...
}
上面的ID
字段如果是non-nil就会被写入。解组时,如果数据库记录有值,它将被设置为 non-nil 值。如果省略 omitempty
标志,封送此结构会将 null
写入数据库。
对于字符串,如果字段为空,您可以使用 omitempty
完全省略该字段。如果要存储空字符串,请省略 omitempty
.
设置
我使用 MySQL 开始了一个项目,因此,我的项目有一些帮助处理空值的帮助程序类型,无论是在 API 上解组传入数据时,还是将数据输入数据库时,然后与之相反,从数据库中提取数据并将所述数据响应到 API.
出于这个问题的目的,我们将处理我拥有的表示字符的结构。
type Character struct {
MongoID primitive.ObjectID `bson:"_id" json:"-"`
ID uint64 `bson:"id" json:"id"`
Name string `bson:"name" json:"name"`
CorporationID uint `bson:"corporation_id" json:"corporation_id"`
AllianceID null.Uint `bson:"alliance_id" json:"alliance_id,omitempty"`
FactionID null.Uint `bson:"faction_id" json:"faction_id,omitempty"`
SecurityStatus float64 `bson:"security_status" json:"security_status"`
NotModifiedCount uint `bson:"not_modified_count" json:"not_modified_count"`
UpdatePriority uint `bson:"update_priority" json:"update_priority"`
Etag null.String `bson:"etag" json:"etag"`
CachedUntil time.Time `bson:"cached_until" json:"cached_until"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}
我想特别关注 null.Uint
类型的 AllianceID 属性,它用以下结构表示:
// Uint is an nullable uint.
type Uint struct {
Uint uint
Valid bool
}
在使用 JSON 和 MySQL 的 API 设置中(即我的设置,但这不是唯一的),这种结构使我能够轻松处理“可为空的值" 而不必处理指针。我一直听说最好避免使用指针,但结构指针除外(切片、结构切片、结构映射等)。如果您有基本类型(int、bool、float 等),请尽量避免使用指向该基本类型的指针。
此类型具有 MarshalJSON
、UnmarshalJSON
、Scan
和 Value
等函数,这些函数中的逻辑利用 Vaild 属性 来确定return 是什么类型的值。这在这个设置下效果非常好。
问题
经过一些研究,我开始意识到 Mongo 比关系数据库更适合我,但是由于 Mongo 文档(无模式)的流动性,我很难理解如何处理可能缺少字段的场景,或者我在 MySQL 中的 属性 通常为 null 的情况,我可以轻松地解组此结构并在逻辑上使用辅助函数, 被处理。此外,当我设置与 Mongo 的连接并从 MySQL 中提取几行并从这些行中创建 Mongo 中的文档时,BSON 层正在编组 Alliance ID 的整个类型和将其粘贴到数据库中。
示例:
"alliance_id" : {
"uint" : NumberLong(99007760),
"valid" : true
},
在 MySQL 中,将调用实现 Valuer 接口的值函数,并且 return 99007760
就是数据库中的值。
另一种情况是 valid 为 false。在 MySQL 中,这意味着空值,当调用 Value 函数时,它将 return nil 并且 mysql 驱动程序将使用 NULL
[=25= 填充字段]
所以我的问题是我该怎么做?我是否需要从头开始并重建我的模型并重做我的应用程序中利用 Valid 属性 和使用 *Pointers
的一些逻辑,或者我可以使用这些帮助程序类型做我想做的事情吗.
我确实想说我已经尝试在bson包上实现Marshaller
和Unmarshaller
接口,文档中的alliane_id仍然设置为json 我上面概述的这种类型的编码版本。我想指出这一点以排除实施这些接口的任何建议。如果我试图实现的目标与 Mongo 的直觉相反,请 link 一些指南可以帮助我实现我正在尝试做的事情。
感谢所有对此提供帮助的人。
像这样处理可选字段的最简单方法是使用指针:
type Character struct {
ID *uint64 `bson:"id,omitempty" json:"id"`
Name string `bson:"name" json:"name"`
...
}
上面的ID
字段如果是non-nil就会被写入。解组时,如果数据库记录有值,它将被设置为 non-nil 值。如果省略 omitempty
标志,封送此结构会将 null
写入数据库。
对于字符串,如果字段为空,您可以使用 omitempty
完全省略该字段。如果要存储空字符串,请省略 omitempty
.