Использование драйвера mongodb go для декодирования документов в структуры с полями нестандартного типа - PullRequest
0 голосов
/ 26 августа 2018

Я новичок как в go, так и в mongodb.Я пытаюсь декодировать DocumentResult в структуру, используя теги bson, и она не работает для пользовательского типа, заключающего в строку.Можно ли это сделать, не меняя тип поля на строку?

    import (
    "context"
    "github.com/mongodb/mongo-go-driver/mongo"
)

type MyDoc struct {
    SomeInt int `bson:"some_int"`
    SomeString string `bson:"some_string,omitempty"`
    CustomType MyType `bson:"custom_type,omitempty"`
}

type MyType string

const myType MyType = "ABCD"

func main() {

    //Connect to db
    client, _ := mongo.Connect(context.Background(), "mongodb://localhost:27017", nil)
    db := client.Database("example_db")
    collection := db.Collection("col")

    //Insert document
    docToInsert := MyDoc{42, "The Answer", myType}
    collection.InsertOne(nil, docToInsert)

    //Retrieve document
    filterDoc := MyDoc{SomeInt: 42}
    resultDoc := &MyDoc{}
    result := collection.FindOne(nil, filterDoc)
    result.Decode(resultDoc)

    println(resultDoc.SomeInt, resultDoc.SomeString, resultDoc.CustomType)

ПЕЧАТНЫЙ РЕЗУЛЬТАТ: "42 The Answer" // "ABCD" отсутствует

Спасибозаранее

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Я пытаюсь декодировать DocumentResult в структуру, используя теги bson, и он не работает для пользовательского типа, заключающего в строку

С вашим текущим MyType документом, которыйбудет храниться в MongoDB следующим образом:

{
  "_id": ObjectId("..."),
  "some_int": NumberLong("42"),
  "some_string": "The Answer",
  "custom_type": "ABCD"
}

Несмотря на то, что базовый тип - string, это может быть сложно декодировать с текущей версией mongo-go-driver (v0.0.12) из-за переноса типа.

Однако, если вы хотите иметь собственный тип как таковой, вы можете вместо этого изменить структуру на встроенное поле .Например:

type MyDoc struct {
    SomeInt    int    `bson:"some_int"`
    SomeString string `bson:"some_string,omitempty"`
    CustomType MyType `bson:"custom_type,omitempty"`
}

type MyType struct {
    Value string `bson:"value,omitempty"`
}

var myType = MyType{Value: "ABCD"}

docToInsert := MyDoc{42, "The Answer", "ABCD"}

insertResult, err := collection.InsertOne(nil, docToInsert)

resultDoc := collection.FindOne(context.Background(), nil)
if err != nil {
    log.Fatal(err)
}
elem := &MyDoc{}
err = resultDoc.Decode(elem)
if err != nil {
    log.Fatal(err)
}
fmt.Println(elem.SomeInt, elem.SomeString, elem.CustomType.Value)
// 42 The Answer ABCD

Документ будет храниться в MongoDB, как показано ниже:

{
  "_id": ObjectId("..."),
  "some_int": NumberLong("42"),
  "some_string": "The Answer",
  "custom_type": {
    "value": "ABCD"
  }
}

В противном случае просто используйте тип string напрямую, поскольку результирующий документ в базе данных будет таким жев качестве версии переноса типа:

type MyDoc struct {
    SomeInt    int    `bson:"some_int"`
    SomeString string `bson:"some_string,omitempty"`
    CustomType string `bson:"custom_type,omitempty"`
} 

Вы также можете найти MongoDB Data Modeling полезной ссылкой.

0 голосов
/ 27 августа 2018

К сожалению, вам не повезло. Текущее состояние официального драйвера mongo go не поддерживает демаршалирование значений string от BSON до значения Go, тип которого является пользовательским типом, имеющим string в качестве базового типа. Это может измениться в будущем, но пока это не поддерживается.

Способ обработки декодирования в поле структуры реализован в bson/decode.go, в настоящее время строка # 387 :

case 0x2:
    str := v.StringValue()
    switch containerType {
    case tString, tEmpty:
        val = reflect.ValueOf(str)
    case tJSONNumber:
        _, err := strconv.ParseFloat(str, 64)
        if err != nil {
            return val, err
        }
        val = reflect.ValueOf(str).Convert(tJSONNumber)

    case tURL:
        u, err := url.Parse(str)
        if err != nil {
            return val, err
        }
        val = reflect.ValueOf(u).Elem()
    default:
        return val, nil
    }

0x02 - тип строки BSON. Попытка декодирования в поле структуры выполняется только в том случае, если тип поля структуры является одним из следующих: string, interface{}, json.Number или url.URL (или указатель на них).

К сожалению, реализация bson.Unmarshaler для вашего пользовательского типа также не помогает, так как это не проверяется в случае полей структуры, только если сама структура реализует его. Но при реализации самой структуры вам придется дублировать структуру с полем, являющимся одним из перечисленных выше поддерживаемых типов (или использовать карту или тип bson.Document).

Это серьезное ограничение со стороны библиотеки, которое очень легко решить, поэтому давайте надеяться на лучшее, что они добавят поддержку для этого в ближайшем будущем.

...