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

Mgo-aggregering:hvordan genbruger man modeltyper til at forespørge og fjerne blandede resultater?

Forespørgslen ovenfor returnerer dokumenter, der "næsten" matcher User dokumenter, men de har også hver brugers indlæg. Så grundlæggende er resultatet en serie af User dokumenter med en Post matrix eller udsnit indlejret .

En måde ville være at tilføje en Posts []*Post feltet til User selv, og vi ville være færdige:

type User struct {
    ID         string    `bson:"_id"`
    Name       string    `bson:"name"`
    Registered time.Time `bson:"registered"`
    Posts      []*Post   `bson:"posts,omitempty"`
}

Selvom dette virker, virker det "overkill" at udvide User med Posts bare for en enkelt forespørgsel. Hvis vi fortsætter ad denne vej, vil vores User type ville blive oppustet med masser af "ekstra" felter til forskellige forespørgsler. For ikke at nævne, om vi udfylder Posts felt og gemme brugeren, ville disse indlæg ende med at blive gemt i User dokument. Ikke hvad vi ønsker.

En anden måde ville være at oprette en UserWithPosts type kopiering User , og tilføjelse af en Posts []*Post Mark. Det er overflødigt at sige, at dette er grimt og ufleksibelt (enhver ændring af User skulle afspejles i UserWithPosts manuelt).

Med Struct Embedding

I stedet for at ændre den originale User , og i stedet for at oprette en ny UserWithPosts skriv fra "scratch", kan vi bruge struct-indlejring (genbruger den eksisterende User og Post typer) med et lille trick:

type UserWithPosts struct {
    User  `bson:",inline"`
    Posts []*Post `bson:"posts"`
}

Bemærk bson tagværdien ",inline" . Dette er dokumenteret på bson.Marshal() og bson.Unmarshal() (vi bruger det til unmarshaling):

Ved at bruge indlejring og ",inline" tag-værdi, UserWithPosts selve typen vil være et gyldigt mål for at opdele User dokumenter, og dets Post []*Post feltet vil være et perfekt valg til de slåede "posts" .

Bruger det:

var uwp *UserWithPosts
it := pipe.Iter()
for it.Next(&uwp) {
    // Use uwp:
    fmt.Println(uwp)
}
// Handle it.Err()

Eller få alle resultater i ét trin:

var uwps []*UserWithPosts
err := pipe.All(&uwps)
// Handle error

Typeerklæringen for UserWithPosts kan være en lokal erklæring eller ikke. Hvis du ikke har brug for det andre steder, kan det være en lokal deklaration i funktionen, hvor du udfører og behandler aggregeringsforespørgslen, så det vil ikke blæse dine eksisterende typer og deklarationer op. Hvis du vil genbruge det, kan du erklære det på pakkeniveau (eksporteret eller ikke-eksporteret) og bruge det, hvor du har brug for det.

Ændring af sammenlægningen

En anden mulighed er at bruge MongoDB's $replaceRoot at "omarrangere" resultatdokumenterne, så en "simpel" struktur dækker dokumenterne perfekt:

// Query users with their posts:
pipe := collUsers.Pipe([]bson.M{
    {
        "$lookup": bson.M{
            "from":         "posts",
            "localField":   "_id",
            "foreignField": "userID",
            "as":           "posts",
        },
    },
    {
        "$replaceRoot": bson.M{
            "newRoot": bson.M{
                "user":  "$$ROOT",
                "posts": "$posts",
            },
        },
    },
})

Med denne remapping kan resultatdokumenterne modelleres således:

type UserWithPosts struct {
    User  *User   `bson:"user"`
    Posts []*Post `bson:"posts"`
}

Bemærk, at mens dette virker, er posts felt af alle dokumenter vil blive hentet fra serveren to gange:én gang som posts feltet for de returnerede dokumenter, og én gang som feltet for user; vi kortlægger/bruger det ikke, men det er til stede i resultatdokumenterne. Så hvis denne løsning vælges, vil user.posts felt skal fjernes f.eks. med et $project fase:

pipe := collUsers.Pipe([]bson.M{
    {
        "$lookup": bson.M{
            "from":         "posts",
            "localField":   "_id",
            "foreignField": "userID",
            "as":           "posts",
        },
    },
    {
        "$replaceRoot": bson.M{
            "newRoot": bson.M{
                "user":  "$$ROOT",
                "posts": "$posts",
            },
        },
    },
    {"$project": bson.M{"user.posts": 0}},
})



  1. mongodb og eller combo

  2. Aktuel topologi understøtter ikke session

  3. Hvad betyder MongoDBs dokumentation, når den siger, at ObjectID'er sandsynligvis er unikke?

  4. Hvad er en ny måde at indstille DateTimeSerializationOptions.Defaults i mongodb c# driver?