MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Agregacja Mgo:jak ponownie używać typów modeli do zapytań i rozmieszczania mieszanych wyników?

Powyższe zapytanie zwraca dokumenty, które „prawie” pasują do User dokumenty, ale mają też posty każdego użytkownika. Tak więc zasadniczo wynikiem jest seria User dokumenty z Post tablica lub plaster osadzone .

Jednym ze sposobów byłoby dodanie Posts []*Post pole do User i skończymy:

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

Chociaż to działa, wydaje się, że rozszerzenie User wydaje się „przesadne” z Posts tylko ze względu na jedno zapytanie. Jeśli będziemy kontynuować tę drogę, nasz User typ zostałby nadęty z dużą ilością „dodatkowych” pól dla różnych zapytań. Nie wspominając o tym, czy wypełnimy Posts i zapisz użytkownika, te posty zostaną zapisane w User dokument. Nie to, czego chcemy.

Innym sposobem byłoby utworzenie UserWithPosts wpisz kopiowanie User i dodanie Posts []*Post pole. Nie trzeba dodawać, że jest to brzydkie i nieelastyczne (wszelkie zmiany wprowadzone w User musiałby zostać odzwierciedlony w UserWithPosts ręcznie).

Z osadzaniem strukturalnym

Zamiast modyfikować oryginalnego User i zamiast tworzyć nowy UserWithPosts wpisz od „scratch”, możemy wykorzystać osadzanie struktur (ponowne wykorzystanie istniejącego User i Post typy) z małą sztuczką:

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

Zwróć uwagę na wartość tagu bson ",inline" . Jest to udokumentowane w bson.Marshal() i bson.Unmarshal() (wykorzystamy go do unmarshalingu):

Używając osadzania i ",inline" wartość tagu, UserWithPosts sam typ będzie prawidłowym celem dla przekazania User dokumenty i ich Post []*Post pole będzie idealnym wyborem dla szukanych "posts" .

Korzystanie z niego:

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

Lub uzyskanie wszystkich wyników w jednym kroku:

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

Deklaracja typu UserWithPosts może, ale nie musi być deklaracją lokalną. Jeśli nie potrzebujesz go gdzie indziej, może to być lokalna deklaracja w funkcji, w której wykonujesz i przetwarzasz zapytanie agregujące, więc nie rozdęje istniejących typów i deklaracji. Jeśli chcesz go ponownie użyć, możesz zadeklarować go na poziomie pakietu (eksportowanym lub nieeksportowanym) i używać go wszędzie, gdzie jest potrzebny.

Modyfikowanie agregacji

Inną opcją jest użycie $replaceRoot MongoDB aby "przeorganizować" dokumenty wynikowe, tak aby "prosta" struktura idealnie pokryła 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",
            },
        },
    },
})

Dzięki temu ponownemu mapowaniu dokumenty wynikowe mogą być modelowane w następujący sposób:

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

Zauważ, że chociaż to działa, posts pole wszystkich dokumentów zostanie pobrane z serwera dwukrotnie:raz jako posts pole zwracanych dokumentów, a raz jako pole user; nie mapujemy / nie używamy go, ale jest on obecny w dokumentach wynikowych. Jeśli więc zostanie wybrane to rozwiązanie, user.posts pole należy usunąć np. z $project etap:

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. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Sortowanie niestandardowe MongoDB

  2. Skopiuj folder z symbolem wieloznacznym z kontenera docker do hosta

  3. Problemy z konfiguracją repliki MongoDB SSL — nieobsługiwany certyfikat

  4. Trzy A bezpieczeństwa MongoDB — uwierzytelnianie, autoryzacja i audyt

  5. Reactivemongo serializuje mapę do BSONDocument