sql >> Database teknologi >  >> NoSQL >> MongoDB

Hvordan ignorerer man nuller, mens man fjerner et MongoDB-dokument?

Problemet er, at de nuværende bson-codecs ikke understøtter kodning / afkodning af string ind i / fra null .

En måde at håndtere dette på er at oprette en brugerdefineret dekoder til string type, hvor vi håndterer null værdier:vi bruger bare den tomme streng (og endnu vigtigere rapporterer ikke fejl).

Brugerdefinerede dekodere er beskrevet af typen bsoncodec.ValueDecoder . De kan registreres i et bsoncodec.Registry , ved hjælp af en bsoncodec.RegistryBuilder for eksempel.

Registre kan indstilles / anvendes på flere niveauer, selv til en hel mongo.Client , eller til en mongo.Database eller bare til en mongo.Collection , når de erhverver dem, som en del af deres muligheder, f.eks. options.ClientOptions.SetRegistry() .

Lad os først se, hvordan vi kan gøre dette for string , og derefter skal vi se, hvordan man forbedrer/genererer løsningen til enhver type.

1. Håndtering af null strenge

Først og fremmest, lad os skabe en brugerdefineret strengdekoder, der kan ændre en null ind i en (n tom) streng:

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
}

OK, og lad os nu se, hvordan man bruger denne tilpassede strengdekoder til en mongo.Client :

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

Fra nu af skal du bruge denne client , hver gang du afkoder resultater til string værdier, denne registrerede nullawareStrDecoder dekoder vil blive kaldt til at håndtere konverteringen, som accepterer bson null værdier og indstiller den tomme streng "" .

Men vi kan gøre det bedre... Læs videre...

2. Håndtering af null værdier af enhver type:"type-neutral" null-bevidst dekoder

En måde ville være at oprette en separat, brugerdefineret dekoder og registrere den for hver type, vi ønsker at håndtere. Det ser ud til at være meget arbejde.

Hvad vi kan (og bør) gøre i stedet er at skabe en enkelt "type-neutral" brugerdefineret dekoder, som kun håndterer null s, og hvis BSON-værdien ikke er null , skal kalde standarddekoderen til at håndtere ikke-null værdi.

Dette er overraskende enkelt:

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
}

Vi skal bare finde ud af, hvad vi skal bruge til nullawareDecoder.defDecoder . Til dette kan vi bruge standardregistret:bson.DefaultRegistry , kan vi slå standarddekoderen op for individuelle typer. Fedt.

Så det, vi gør nu, er at registrere en værdi af vores nullawareDecoder for alle typer, vi ønsker at håndtere null s for. Det er ikke så svært. Vi lister bare de typer (eller værdier af disse typer), vi ønsker dette for, og vi kan tage os af det hele med en simpel løkke:

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)

I eksemplet ovenfor registrerede jeg null-bevidste dekodere for string , int og int32 , men du kan udvide denne liste til din smag, bare tilføje værdier af de ønskede typer til customValues udsnit ovenfor.



  1. mongodb:hvordan kan jeg se udførelsestiden for den samlede kommando?

  2. MongoDB Multikey indekser &indeks skæringsgrænser

  3. mongoDB:Oprettelse af et objekt-id for hvert nyt barn, der føjes til array-feltet

  4. Yeoman, Mongoose og MongoDB Stilladser