sql >> データベース >  >> NoSQL >> MongoDB

MongoDBドキュメントのマーシャリングを解除するときにnullを無視するにはどうすればよいですか?

    問題は、現在のbsonコーデックがstringのエンコード/デコードをサポートしていないことです。 nullへ/から 。

    これを処理する1つの方法は、stringのカスタムデコーダーを作成することです。 nullを処理するタイプ 値:空の文字列を使用するだけです(さらに重要なことに、エラーを報告しません)。

    カスタムデコーダーは、タイプbsoncodec.ValueDecoderで記述されます。 。 bsoncodec.Registryで登録できます 、bsoncodec.RegistryBuilderを使用 たとえば。

    レジストリは、mongo.Client全体に対しても、複数のレベルで設定/適用できます。 、またはmongo.Database または単にmongo.Collection 、それらを取得するとき、それらのオプションの一部として、例えば。 options.ClientOptions.SetRegistry()

    まず、stringに対してこれを行う方法を見てみましょう。 、次に、ソリューションを任意のタイプに改善/一般化する方法を説明します。

    1。 nullの処理 文字列

    まず最初に、nullを変換できるカスタム文字列デコーダーを作成しましょう (n個の空の)文字列に:

    import (
        "go.mongodb.org/mongo-driver/bson/bsoncodec"
        "go.mongodb.org/mongo-driver/bson/bsonrw"
        "go.mongodb.org/mongo-driver/bson/bsontype"
    )
    
    type nullawareStrDecoder struct{}
    
    func (nullawareStrDecoder) DecodeValue(dctx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
        if !val.CanSet() || val.Kind() != reflect.String {
            return errors.New("bad type or not settable")
        }
        var str string
        var err error
        switch vr.Type() {
        case bsontype.String:
            if str, err = vr.ReadString(); err != nil {
                return err
            }
        case bsontype.Null: // THIS IS THE MISSING PIECE TO HANDLE NULL!
            if err = vr.ReadNull(); err != nil {
                return err
            }
        default:
            return fmt.Errorf("cannot decode %v into a string type", vr.Type())
        }
    
        val.SetString(str)
        return nil
    }
    

    では、このカスタム文字列デコーダーをmongo.Clientに利用する方法を見てみましょう。 :

    clientOpts := options.Client().
        ApplyURI("mongodb://localhost:27017/").
        SetRegistry(
            bson.NewRegistryBuilder().
                RegisterDecoder(reflect.TypeOf(""), nullawareStrDecoder{}).
                Build(),
        )
    client, err := mongo.Connect(ctx, clientOpts)
    

    今後は、このclientを使用してください 、結果をstringにデコードするときはいつでも 値、この登録されたnullawareStrDecoder デコーダーは、bson nullを受け入れる変換を処理するために呼び出されます Go empty string ""の値と設定 。

    しかし、私たちはもっとうまくやることができます...続きを読む...

    2。 nullの処理 任意のタイプの値:「タイプニュートラル」ヌル対応デコーダー

    1つの方法は、個別のカスタムデコーダーを作成し、処理するタイプごとに登録することです。大変な作業のようです。

    代わりに行うことができる(そしてすべきである)のは、nullだけを処理する単一の「タイプニュートラル」カスタムデコーダーを作成することです。 s、およびBSON値がnullでない場合 、デフォルトのデコーダーを呼び出して、null以外を処理する必要があります 値。

    これは驚くほど簡単です:

    type nullawareDecoder struct {
        defDecoder bsoncodec.ValueDecoder
        zeroValue  reflect.Value
    }
    
    func (d *nullawareDecoder) DecodeValue(dctx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
        if vr.Type() != bsontype.Null {
            return d.defDecoder.DecodeValue(dctx, vr, val)
        }
    
        if !val.CanSet() {
            return errors.New("value not settable")
        }
        if err := vr.ReadNull(); err != nil {
            return err
        }
        // Set the zero value of val's type:
        val.Set(d.zeroValue)
        return nil
    }
    

    nullawareDecoder.defDecoderに何を使用するかを理解する必要があります 。このために、デフォルトのレジストリを使用できます:bson.DefaultRegistry 、個々のタイプのデフォルトデコーダーを検索する場合があります。かっこいい。

    したがって、ここで行うのは、nullawareDecoderの値を登録することです。 処理するすべてのタイプについてnull s。それほど難しいことではありません。これが必要なタイプ(またはそれらのタイプの値)をリストするだけで、単純なループですべてを処理できます:

    customValues := []interface{}{
        "",       // string
        int(0),   // int
        int32(0), // int32
    }
    
    rb := bson.NewRegistryBuilder()
    for _, v := range customValues {
        t := reflect.TypeOf(v)
        defDecoder, err := bson.DefaultRegistry.LookupDecoder(t)
        if err != nil {
            panic(err)
        }
        rb.RegisterDecoder(t, &nullawareDecoder{defDecoder, reflect.Zero(t)})
    }
    
    clientOpts := options.Client().
        ApplyURI("mongodb://localhost:27017/").
        SetRegistry(rb.Build())
    client, err := mongo.Connect(ctx, clientOpts)
    

    上記の例では、stringのnull対応デコーダーを登録しました 、int およびint32 、ただし、このリストを好みに合わせて拡張できます。必要なタイプの値をcustomValuesに追加するだけです。 上のスライス。



    1. mongodbは実行されていますか?

    2. Meteor:予期しないmongo終了コード100。再起動。mongoサーバーを起動できません。

    3. MongoDB$dateToStringフォーマット指定子

    4. MongoDB $ round