mongodb-go-driver/bson 结构到 bson.Document 编码
mongodb-go-driver/bson struct to bson.Document encoding
我正在与 https://github.com/mongodb/mongo-go-driver 合作,并且
目前正在尝试实现此类结构的部分更新
type NoteUpdate struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
Title string `json:"title" bson:"title,omitempty"`
Content string `json:"content" bson:"content,omitempty"`
ChangedAt int64 `json:"changed_at" bson:"changed_at"`
}
例如,如果我有
noteUpdate := NoteUpdate{ Title: "New Title" }
那么我希望存储文档中唯一的"title"字段会被更改。
我需要写一些类似
的东西
collection.FindOneAndUpdate(context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
// I need to encode non-empty fields here
bson.NewDocument(bson.EC.SubDocument("$set", bson.NewDocument(...)))
)
问题是我不想用 bson.EC.String(...)
或 bson.EC.Int64(...)
手动编码每个非空字段。我尝试使用 bson.EC.InterfaceErr(...)
但出现错误
Cannot create element for type *models.NoteUpdate, try using bsoncodec.ConstructElementErr
很遗憾,bsoncodec中没有这个功能。我发现的唯一方法是创建包装器
type SetWrapper struct {
Set interface{} `bson:"$set,omitempty"`
}
并像
一样使用它
partialUpdate := &NoteUpdate{
ID: "some-note-id",
Title: "Some new title",
}
updateParam := SetWrapper{Set: partialUpdate}
collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
updateParam,
)
它有效,但是否可以使用 bson/bsoncodec 文档生成器实现相同的效果?
更新。我的问题的完整背景:
我为 部分 更新 "Note" 文档(存储在 MongoDB 中)编写了 REST 端点。我现在拥有的代码:
var noteUpdate models.NoteUpdate
ctx.BindJSON(¬eUpdate)
//omit validation and errors handling
updateParams := services.SetWrapper{Set: noteUpdate}
res := collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
updateParams,
findopt.OptReturnDocument(option.After),
)
我想要的代码
var noteUpdate models.NoteUpdate
ctx.BindJSON(¬eUpdate)
//omit validation and errors handling
res := collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
bson.NewDocument(
//bsoncodec.ConstructElement doesn't exists
bsoncodec.ConstructElement("$set", ¬eUpdate)),
),
findopt.OptReturnDocument(option.After),
)
我不想要的代码
var noteUpdate models.NoteUpdate
ctx.BindJSON(¬eUpdate)
//omit validation and errors handling
bsonNote := bson.NewDocument()
if noteUpdate.Title != "" {
bsonNote.Append(bson.EC.String("title", noteUpdate.Title))
}
if noteUpdate.Content != "" {
bsonNote.Append(bson.EC.String("content", noteUpdate.Content))
}
//..setting the rest of the fields...
res := collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
bson.NewDocument(bson.EC.SubDocument("$set", bsonNote)),
findopt.OptReturnDocument(option.After),
)
所以,确切的问题是 - 有没有什么方法可以基于 bson
标签动态构建 *bson.Document(没有像我的 SetWrapper 这样的预定义包装器)?
很遗憾,目前不支持此功能。
您可以创建一个辅助函数,它 "converts" 一个 bson.Document
的结构值,如下所示:
func toDoc(v interface{}) (doc *bson.Document, err error) {
data, err := bson.Marshal(v)
if err != nil {
return
}
err = bson.Unmarshal(data, &doc)
return
}
那么可以这样使用:
partialUpdate := &NoteUpdate{
Title: "Some new title",
}
doc, err := toDoc(partialUpdate)
// check error
res := c.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", "some-note-id")),
bson.NewDocument(bson.EC.SubDocument("$set", doc)),
)
希望ElementConstructor.Interface()
将来会改进并允许直接传递结构值或指向结构值的指针。
我正在与 https://github.com/mongodb/mongo-go-driver 合作,并且 目前正在尝试实现此类结构的部分更新
type NoteUpdate struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
Title string `json:"title" bson:"title,omitempty"`
Content string `json:"content" bson:"content,omitempty"`
ChangedAt int64 `json:"changed_at" bson:"changed_at"`
}
例如,如果我有
noteUpdate := NoteUpdate{ Title: "New Title" }
那么我希望存储文档中唯一的"title"字段会被更改。
我需要写一些类似
的东西collection.FindOneAndUpdate(context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
// I need to encode non-empty fields here
bson.NewDocument(bson.EC.SubDocument("$set", bson.NewDocument(...)))
)
问题是我不想用 bson.EC.String(...)
或 bson.EC.Int64(...)
手动编码每个非空字段。我尝试使用 bson.EC.InterfaceErr(...)
但出现错误
Cannot create element for type *models.NoteUpdate, try using bsoncodec.ConstructElementErr
很遗憾,bsoncodec中没有这个功能。我发现的唯一方法是创建包装器
type SetWrapper struct {
Set interface{} `bson:"$set,omitempty"`
}
并像
一样使用它partialUpdate := &NoteUpdate{
ID: "some-note-id",
Title: "Some new title",
}
updateParam := SetWrapper{Set: partialUpdate}
collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
updateParam,
)
它有效,但是否可以使用 bson/bsoncodec 文档生成器实现相同的效果?
更新。我的问题的完整背景: 我为 部分 更新 "Note" 文档(存储在 MongoDB 中)编写了 REST 端点。我现在拥有的代码:
var noteUpdate models.NoteUpdate
ctx.BindJSON(¬eUpdate)
//omit validation and errors handling
updateParams := services.SetWrapper{Set: noteUpdate}
res := collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
updateParams,
findopt.OptReturnDocument(option.After),
)
我想要的代码
var noteUpdate models.NoteUpdate
ctx.BindJSON(¬eUpdate)
//omit validation and errors handling
res := collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
bson.NewDocument(
//bsoncodec.ConstructElement doesn't exists
bsoncodec.ConstructElement("$set", ¬eUpdate)),
),
findopt.OptReturnDocument(option.After),
)
我不想要的代码
var noteUpdate models.NoteUpdate
ctx.BindJSON(¬eUpdate)
//omit validation and errors handling
bsonNote := bson.NewDocument()
if noteUpdate.Title != "" {
bsonNote.Append(bson.EC.String("title", noteUpdate.Title))
}
if noteUpdate.Content != "" {
bsonNote.Append(bson.EC.String("content", noteUpdate.Content))
}
//..setting the rest of the fields...
res := collection.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
bson.NewDocument(bson.EC.SubDocument("$set", bsonNote)),
findopt.OptReturnDocument(option.After),
)
所以,确切的问题是 - 有没有什么方法可以基于 bson
标签动态构建 *bson.Document(没有像我的 SetWrapper 这样的预定义包装器)?
很遗憾,目前不支持此功能。
您可以创建一个辅助函数,它 "converts" 一个 bson.Document
的结构值,如下所示:
func toDoc(v interface{}) (doc *bson.Document, err error) {
data, err := bson.Marshal(v)
if err != nil {
return
}
err = bson.Unmarshal(data, &doc)
return
}
那么可以这样使用:
partialUpdate := &NoteUpdate{
Title: "Some new title",
}
doc, err := toDoc(partialUpdate)
// check error
res := c.FindOneAndUpdate(
context.Background(),
bson.NewDocument(bson.EC.String("_id", "some-note-id")),
bson.NewDocument(bson.EC.SubDocument("$set", doc)),
)
希望ElementConstructor.Interface()
将来会改进并允许直接传递结构值或指向结构值的指针。