mongodb-go-driver / структура bson для bson. Кодировка документа - PullRequest
0 голосов
/ 02 ноября 2018

Я работаю с 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(&noteUpdate)    
//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(&noteUpdate)    
//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", &noteUpdate)),
        ),
    findopt.OptReturnDocument(option.After),
)

Код, который я не хочу иметь

var noteUpdate models.NoteUpdate
ctx.BindJSON(&noteUpdate)
//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)?

1 Ответ

0 голосов
/ 05 ноября 2018

К сожалению, в настоящее время это не поддерживается.

Вы можете создать вспомогательную функцию, которая "преобразует" значение структуры в 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() улучшится в будущем и позволит передавать значения структуры или указатели для непосредственного структурирования значений.

...