webentwicklung-frage-antwort-db.com.de

Verwenden des mongodb go-Treibers zum Dekodieren von Dokumenten in Strukturen mit benutzerdefinierten Typfeldern

Ich bin ein Anfänger in Go und Mongodb. Ich versuche, eine DocumentResult mit bson-Tags in eine Struktur zu dekodieren, und es funktioniert nicht für einen benutzerdefinierten Typ, der eine Zeichenfolge umschließt. Kann dies durchgeführt werden, ohne den Feldtyp in eine Zeichenfolge zu ändern?

    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)

DRUCKERGEBNIS: "42 Die Antwort" // "ABCD" fehlt

Danke im Voraus

3
amz

Leider hast du kein Glück. Der aktuelle Status des offiziellen Mongo-Go-Treibers unterstützt nicht das Aufheben der Zuordnung von string-Werten von BSON zu einem Go-Wert, dessen Typ ein benutzerdefinierter Typ mit string als zugrunde liegendem Typ ist. Dies kann sich in Zukunft ändern, wird jedoch vorerst nicht unterstützt.

Die Art und Weise, wie die Dekodierung in ein Strukturfeld erfolgt, ist in bson/decode.go implementiert, derzeit Zeile # 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 ist der BSON-String-Typ. Es wird nur versucht, in das Strukturfeld zu dekodieren, wenn der Typ des Strukturfelds einer der folgenden ist: string, interface{}, json.Number oder url.URL (oder ein Zeiger auf diese).

Leider hilft es auch nicht, bson.Unmarshaler auf Ihrem benutzerdefinierten Typ zu implementieren, da es bei Strukturfeldern nur dann nicht aktiviert ist, wenn die Struktur es selbst implementiert. Um die Struktur selbst zu implementieren, müssten Sie die Struktur duplizieren, wobei das Feld einer der oben aufgeführten unterstützten Typen ist (oder Sie verwenden eine Map oder einen bson.Document -Typ).

Dies ist eine schwerwiegende Einschränkung für die Bibliothek, die sehr leicht gelöst werden kann. Hoffen wir also, dass sie dies in naher Zukunft unterstützen.

1
icza

Ich versuche, ein DocumentResult mithilfe von bson-Tags in eine Struktur zu dekodieren, und es funktioniert nicht für einen benutzerdefinierten Typ, der eine Zeichenfolge umschließt

Mit Ihrer aktuellen MyType wäre das in MongoDB gespeicherte Dokument wie folgt:

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

Obwohl es sich bei dem zugrunde liegenden Typ um eine string handelt, kann die Dekodierung mit der aktuellen Version von mongo-go-driver (v0.0.12) aufgrund des Typumbruchs schwierig sein.

Wenn Sie jedoch einen benutzerdefinierten Typ als solchen möchten, können Sie die Struktur in ein eingebettetes Feld ändern. Zum Beispiel:

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

Das Dokument würde wie folgt in MongoDB gespeichert:

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

Andernfalls verwenden Sie einfach den Typ string direkt, da das resultierende Dokument in der Datenbank mit der Typumbruchversion identisch ist:

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

Möglicherweise finden Sie auch MongoDB Data Modeling eine nützliche Referenz.

2
Wan Bachtiar