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

Mgo agregace:jak znovu použít typy modelů k dotazování a uvolnění smíšených výsledků?

Výše uvedený dotaz vrací dokumenty, které "téměř" odpovídají User dokumenty, ale mají také příspěvky jednotlivých uživatelů. Takže v podstatě výsledkem je řada User dokumenty s Post pole nebo řez vložený .

Jedním ze způsobů by bylo přidat Posts []*Post do pole User a měli bychom hotovo:

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

I když to funguje, zdá se "přehnané" rozšířit User s Posts jen kvůli jedinému dotazu. Pokud bychom pokračovali touto cestou, náš User typ by se naplnil spoustou „extra“ polí pro různé dotazy. Nemluvě o tom, jestli vyplňujeme Posts pole a uložit uživatele, tyto příspěvky by skončily uloženy uvnitř User dokument. Ne to, co chceme.

Dalším způsobem by bylo vytvořit UserWithPosts zadejte kopírování User a přidáním Posts []*Post pole. Netřeba dodávat, že je to ošklivé a neflexibilní (jakékoli změny provedené v User by se muselo projevit v UserWithPosts ručně).

Se strukturovaným vkládáním

Místo úpravy původního User a místo vytvoření nového UserWithPosts zadejte od začátku, můžeme použít vkládání struktur (opětovné použití stávajícího User a Post typy) s malým trikem:

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

Všimněte si hodnoty značky bson ",inline" . To je zdokumentováno na bson.Marshal() a bson.Unmarshal() (použijeme jej pro unmarshaling):

Pomocí vkládání a ",inline" hodnota značky, UserWithPosts samotný typ bude platným cílem pro odstranění User dokumenty a jeho Post []*Post pole bude perfektní volbou pro vyhledané "posts" .

Použití:

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

Nebo získání všech výsledků v jednom kroku:

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

Deklarace typu UserWithPosts může nebo nemusí být místní deklarací. Pokud to jinde nepotřebujete, může to být lokální deklarace ve funkci, kde spouštíte a zpracováváte agregační dotaz, takže nenadmou vaše stávající typy a deklarace. Pokud jej chcete znovu použít, můžete jej deklarovat na úrovni balíčku (exportovaný nebo neexportovaný) a používat jej, kdekoli jej potřebujete.

Úprava agregace

Další možností je použít $replaceRoot MongoDB k "přeuspořádání" výsledných dokumentů, takže "jednoduchá" struktura dokonale pokryje dokumenty:

// 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",
            },
        },
    },
})

S tímto přemapováním lze výsledné dokumenty modelovat takto:

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

Všimněte si, že zatímco to funguje, posts pole všech dokumentů bude načteno ze serveru dvakrát:jednou jako posts pole vrácených dokumentů a jednou jako pole user; nemapujeme / nepoužíváme, ale je přítomen ve výsledných dokumentech. Pokud tedy zvolíte toto řešení, user.posts pole by mělo být odstraněno např. s $project fáze:

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. Zjistěte, zda je objekt změněn v pre-save hook mongoose

  2. parametr maxmemory v redis.conf

  3. Použití Redis pro fronty pro více aplikací Laravel na jednom serveru

  4. Funkce MapReduce v MongoDB - Seskupení dokumentu podle ID