sql >> Databáze >  >> NoSQL >> MongoDB

Jak ignorovat hodnoty null při odstraňování dokumentu MongoDB?

Problém je v tom, že současné kodeky bson nepodporují kódování / dekódování string do / z null .

Jedním ze způsobů, jak to zvládnout, je vytvořit vlastní dekodér pro string typ, ve kterém zpracováváme null hodnoty:použijeme pouze prázdný řetězec (a co je důležitější, nehlásíme chybu).

Vlastní dekodéry jsou popsány typem bsoncodec.ValueDecoder . Lze je zaregistrovat na bsoncodec.Registry pomocí bsoncodec.RegistryBuilder například.

Registry lze nastavit / použít na více úrovních, dokonce i na celý mongo.Client nebo do mongo.Database nebo jen do mongo.Collection , při jejich pořízení v rámci svých opcí, např. options.ClientOptions.SetRegistry() .

Nejprve se podívejme, jak to můžeme udělat pro string a dále uvidíme, jak zlepšit / zobecnit řešení na jakýkoli typ.

1. Zpracování null řetězce

Nejprve si vytvořte vlastní dekodér řetězců, který dokáže změnit null do (n prázdného) řetězce:

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
}

Dobře, a nyní se podívejme, jak využít tento vlastní dekodér řetězců pro mongo.Client :

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

Od této chvíle pomocí tohoto client , kdykoli dekódujete výsledky do string hodnoty, tento registroval nullawareStrDecoder bude zavolán dekodér, který provede konverzi, která akceptuje bson null hodnoty a nastaví Go prázdný řetězec "" .

Ale můžeme to udělat lépe... Čtěte dále...

2. Zpracování null hodnoty libovolného typu:"typově neutrální" dekodér s nulovou znalostí

Jedním ze způsobů by bylo vytvořit samostatný vlastní dekodér a zaregistrovat jej pro každý typ, který chceme zpracovávat. Zdá se, že je to hodně práce.

Místo toho můžeme (a měli bychom) vytvořit jediný „typově neutrální“ vlastní dekodér, který zpracovává pouze null s, a pokud hodnota BSON není null , by měl zavolat výchozí dekodér, aby zpracoval nenull hodnotu.

Je to překvapivě jednoduché:

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
}

Musíme jen vymyslet, co použít pro nullawareDecoder.defDecoder . K tomu můžeme použít výchozí registr:bson.DefaultRegistry , můžeme pro jednotlivé typy vyhledat výchozí dekodér. Skvělé.

Nyní tedy zaregistrujeme hodnotu našeho nullawareDecoder pro všechny typy chceme zpracovat null s pro. Není to tak těžké. Vypíšeme pouze typy (nebo hodnoty těchto typů), pro které to chceme, a o vše se můžeme postarat pomocí jednoduché smyčky:

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)

Ve výše uvedeném příkladu jsem zaregistroval dekodéry s nulovou hodnotou pro string , int a int32 , ale tento seznam můžete rozšířit podle svých představ, stačí přidat hodnoty požadovaných typů do customValues plátek výše.



  1. Pěkný tisk v prostředí MongoDB jako výchozí

  2. O prefixu char b v klientovi Python3.4.1 se připojte k redis

  3. Redis skenování přeskakování kláves

  4. Ověření uživatele baňky