私はgoとmongodbの両方の初心者です。 bsonタグを使用してDocumentResult
を構造体にデコードしようとしましたが、文字列をラップするカスタムタイプでは機能しません。フィールドのタイプを文字列に変更せずに実行できますか?
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"がありません
前もって感謝します
残念ながらあなたは運が悪い。公式のmongo goドライバーの現在の状態は、BSONからstring
を基本型として持つカスタム型である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
type)。
これはライブラリの一部に対する重大な制限であり、非常に簡単に解決できるため、近い将来にサポートが追加されることを願っています。
Bsonタグを使用してDocumentResultを構造体にデコードしようとしましたが、文字列をラップするカスタムタイプでは機能しません
現在の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 が役立つリファレンスを見つけるかもしれません。