Я работаю с 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" }
Тогда я ожидаю, что будет изменено единственное поле «заголовок» в сохраненном документе.
Мне нужно написать что-то вроде
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(...)
, но получил ошибку
Невозможно создать элемент для типа * models.NoteUpdate, попробуйте использовать 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?
UPD. Полный контекст моего вопроса:
Я написал конечную точку REST для , частично , обновляющего документы «Note» (хранящиеся в MongoDB). Код, который у меня сейчас есть:
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.Document динамически на основе тегов bson
(без предопределенных оболочек, таких как мой SetWrapper)?