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

Suma zagnieżdżonej tablicy w node.js mongodb

Zacznijmy od podstawowego zastrzeżenia, że ​​główna część odpowiedzi na problem została już opisana tutaj pod adresem Znajdź w podwójnie zagnieżdżonej tablicy MongoDB . I „dla porządku” Podwójny dotyczy również Potrójnego lub Czwór lub DOWOLNY poziom zagnieżdżenia jako w zasadzie ta sama zasada ZAWSZE .

Innym głównym punktem każdej odpowiedzi jest również Nie zagnieżdżaj tablic , ponieważ jak wyjaśniono w tej odpowiedzi (i powtórzyłem to wiele razy ), niezależnie od powodu „myślisz” masz do "zagnieżdżania" w rzeczywistości nie daje korzyści, które według ciebie będzie. W rzeczywistości "zagnieżdżanie" naprawdę tylko utrudnia życie.

Zagnieżdżone problemy

Główne błędne przekonanie o jakimkolwiek tłumaczeniu struktury danych z modelu „relacyjnego” jest prawie zawsze interpretowane jako „dodaj poziom zagnieżdżonej tablicy” dla każdego powiązanego modelu. To, co tutaj przedstawiasz, nie jest wyjątkiem od tego błędnego przekonania, ponieważ wydaje się, że jest „znormalizowane” tak, aby każda podtablica zawierała elementy powiązane ze swoim rodzicem.

MongoDB jest bazą danych opartą na "dokumentach", więc w zasadzie pozwala to zrobić lub w rzeczywistości dowolną zawartość struktury danych, którą w zasadzie chcesz. Nie oznacza to jednak, że dane w takiej formie są łatwe w obsłudze lub rzeczywiście są praktyczne w rzeczywistym celu.

Wypełnijmy schemat rzeczywistymi danymi, aby zademonstrować:

{
  "_id": 1,
  "first_level": [
    {
      "first_item": "A",
      "second_level": [
        {
          "second_item": "A",
          "third_level": [
            { 
              "third_item": "A",
              "forth_level": [
                { 
                  "price": 1,
                  "sales_date": new Date("2018-10-31"),
                  "quantity": 1
                },
                { 
                  "price": 1,
                  "sales_date": new Date("2018-11-01"),
                  "quantity": 1
                },
                { 
                  "price": 1,
                  "sales_date": new Date("2018-11-02"),
                  "quantity": 1
                },
              ]
            },
            { 
              "third_item": "B",
              "forth_level": [
                { 
                  "price": 1,
                  "sales_date": new Date("2018-10-31"),
                  "quantity": 1
                },
              ]
            }
          ]
        },
        {
          "second_item": "A",
          "third_level": [
            { 
              "third_item": "B",
              "forth_level": [
                { 
                  "price": 1,
                  "sales_date": new Date("2018-11-03"),
                  "quantity": 1
                },
              ]
            }
          ]
        }
      ]
    },
    {
      "first_item": "A",
      "second_level": [
        {
          "second_item": "B",
          "third_level": [
            { 
              "third_item": "A",
              "forth_level": [
                { 
                  "price": 1,
                  "sales_date": new Date("2018-11-03"),
                  "quantity": 1
                },
              ]
            }
          ]
        }
      ]
    }
  ]
},
{
  "_id": 2,
  "first_level": [
    {
      "first_item": "A",
      "second_level": [
        {
          "second_item": "A",
          "third_level": [
            { 
              "third_item": "A",
              "forth_level": [
                { 
                  "price": 2,
                  "sales_date": new Date("2018-11-03"),
                  "quantity": 1
                },
                { 
                  "price": 1,
                  "sales_date": new Date("2018-10-31"),
                  "quantity": 1
                },
                { 
                  "price": 1,
                  "sales_date": new Date("2018-11-03"),
                  "quantity": 1
                }
              ]
            }
          ]
        }
      ]
    }
  ]
},
{
  "_id": 3,
  "first_level": [
    {
      "first_item": "A",
      "second_level": [
        {
          "second_item": "B",
          "third_level": [
            { 
              "third_item": "A",
              "forth_level": [
                { 
                  "price": 1,
                  "sales_date": new Date("2018-11-03"),
                  "quantity": 1
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

To "trochę" różni się od struktury w pytaniu, ale w celach demonstracyjnych ma to, na co musimy się przyjrzeć. Głównie w dokumencie znajduje się tablica, która zawiera elementy z podtablicą, która z kolei ma elementy w podtablicy i tak dalej. „normalizacja” tutaj jest oczywiście przez identyfikatory na każdym „poziomie” jako „typ przedmiotu” lub cokolwiek, co faktycznie masz.

Sedno problemu polega na tym, że chcesz po prostu „niektórych” danych z tych zagnieżdżonych tablic, a MongoDB naprawdę chce tylko zwrócić „dokument”, co oznacza, że ​​musisz wykonać pewną manipulację, aby dostać się do tych pasujących „pod- przedmioty”.

Nawet w kwestii „prawidłowo” wybranie dokumentu, który pasuje do wszystkich tych „podkryteriów” wymaga intensywnego użycia $elemMatch w celu uzyskania poprawnej kombinacji warunków na każdym poziomie elementów tablicy. Nie możesz użyć bezpośrednio "Zapisu z kropkami" ze względu na potrzebę tych wiele warunków . Bez $elemMatch oświadczenia, w których nie otrzymujesz dokładnej „kombinacji” i po prostu otrzymujesz dokumenty, w których warunek był spełniony dla dowolnego element tablicy.

Co do faktycznego „filtrowania zawartości tablicy” to jest właściwie część dodatkowej różnicy:

db.collection.aggregate([
  { "$match": {
    "first_level": {
      "$elemMatch": {
        "first_item": "A",
        "second_level": {
          "$elemMatch": {
            "second_item": "A",
            "third_level": {
              "$elemMatch": {
                "third_item": "A",
                "forth_level": {
                  "$elemMatch": {
                    "sales_date": {
                      "$gte": new Date("2018-11-01"),
                      "$lt": new Date("2018-12-01")
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }},
  { "$addFields": {
    "first_level": {
      "$filter": {
        "input": {
          "$map": {
            "input": "$first_level",
            "in": {
              "first_item": "$$this.first_item",
              "second_level": {
                "$filter": {
                  "input": {
                    "$map": {
                      "input": "$$this.second_level",
                      "in": {
                        "second_item": "$$this.second_item",
                        "third_level": {
                          "$filter": {
                            "input": {
                              "$map": {
                                "input": "$$this.third_level",
                                 "in": {
                                   "third_item": "$$this.third_item",
                                   "forth_level": {
                                     "$filter": {
                                       "input": "$$this.forth_level",
                                       "cond": {
                                         "$and": [
                                           { "$gte": [ "$$this.sales_date", new Date("2018-11-01") ] },
                                           { "$lt": [ "$$this.sales_date", new Date("2018-12-01") ] }
                                         ]
                                       }
                                     }
                                   }
                                 } 
                              }
                            },
                            "cond": {
                              "$and": [
                                { "$eq": [ "$$this.third_item", "A" ] },
                                { "$gt": [ { "$size": "$$this.forth_level" }, 0 ] }
                              ]
                            }
                          }
                        }
                      }
                    }
                  },
                  "cond": {
                    "$and": [
                      { "$eq": [ "$$this.second_item", "A" ] },
                      { "$gt": [ { "$size": "$$this.third_level" }, 0 ] }
                    ]
                  }
                }
              }
            }
          }
        },
        "cond": {
          "$and": [
            { "$eq": [ "$$this.first_item", "A" ] },
            { "$gt": [ { "$size": "$$this.second_level" }, 0 ] }
          ]
        } 
      }
    }
  }},
  { "$unwind": "$first_level" },
  { "$unwind": "$first_level.second_level" },
  { "$unwind": "$first_level.second_level.third_level" },
  { "$unwind": "$first_level.second_level.third_level.forth_level" },
  { "$group": {
    "_id": {
      "date": "$first_level.second_level.third_level.forth_level.sales_date",
      "price": "$first_level.second_level.third_level.forth_level.price",
    },
    "quantity_sold": {
      "$avg": "$first_level.second_level.third_level.forth_level.quantity"
    } 
  }},
  { "$group": {
    "_id": "$_id.date",
    "prices": {
      "$push": {
        "price": "$_id.price",
        "quanity_sold": "$quantity_sold"
      }
    },
    "quanity_sold": { "$avg": "$quantity_sold" }
  }}
])

Najlepiej jest to opisać jako „brudny” i „zaangażowany”. Nasze początkowe zapytanie o wybór dokumentów to nie tylko $elemMatch więcej niż kęs, ale potem mamy kolejne $filter i $map przetwarzanie dla każdego poziomu tablicy. Jak wspomniano wcześniej, jest to wzór bez względu na to, ile faktycznie jest poziomów.

Możesz alternatywnie wykonać $unwind i $match kombinacji zamiast filtrowania tablic w miejscu, ale powoduje to dodatkowe obciążenie $odpręż zanim niechciana zawartość zostanie usunięta, więc we współczesnych wydaniach MongoDB ogólnie lepszą praktyką jest $filtr najpierw z tablicy.

Miejscem końcowym jest tutaj $group przez elementy, które faktycznie znajdują się w tablicy, więc w końcu trzeba $rozwiń każdy poziom tablic i tak przed tym.

Rzeczywiste „grupowanie” jest wtedy na ogół proste przy użyciu data_sprzedaży i cena właściwości dla pierwszego akumulacja, a następnie dodanie kolejnego etapu do $push inna cena wartości, dla których chcesz zgromadzić średnią w każdej dacie jako sekundę akumulacja.

UWAGA :Rzeczywista obsługa dat może się różnić w praktyce w zależności od szczegółowości ich przechowywania. W tym przykładzie wszystkie daty są już zaokrąglone do początku każdego „dnia”. Jeśli rzeczywiście musisz gromadzić rzeczywiste wartości „daty/godziny”, prawdopodobnie naprawdę potrzebujesz konstrukcji takiej lub podobnej:

{ "$group": {
  "_id": {
    "date": {
      "$dateFromParts": {
        "year": { "$year": "$first_level.second_level.third_level.forth_level.sales_date" },
        "month": { "$month": "$first_level.second_level.third_level.forth_level.sales_date" },
        "day": { "$dayOfMonth": "$first_level.second_level.third_level.forth_level.sales_date" }
      }
    }.
    "price": "$first_level.second_level.third_level.forth_level.price"
  }
  ...
}}

Korzystanie z $dateFromParts i inne operatory agregacji dat aby wyodrębnić informacje „dzień” i przedstawić datę wstecz w tej formie do akumulacji.

Rozpoczęcie denormalizacji

Z powyższego „bałaganu” powinno jasno wynikać, że praca z zagnieżdżonymi tablicami nie jest łatwa. Takie struktury generalnie nie były nawet możliwe do atomowej aktualizacji w wydaniach wcześniejszych niż MongoDB 3.6, a nawet jeśli nigdy ich nie zaktualizowałeś lub nie żyłeś z zastępowaniem w zasadzie całej tablicy, nadal nie są łatwe do zapytania. To jest to, co jest Ci pokazywane.

Gdzie musisz mieć zawartość tablicy w dokumencie nadrzędnym, generalnie zaleca się "spłaszczyć" i „denormalizować” takie struktury. Może się to wydawać sprzeczne z myśleniem relacyjnym, ale w rzeczywistości jest to najlepszy sposób obsługi takich danych ze względu na wydajność:

{
  "_id": 1,
  "data": [
    {
      "first_item": "A",
      "second_item": "A",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-10-31"),
      "quantity": 1
    },

    { 
      "first_item": "A",
      "second_item": "A",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-11-01"),
      "quantity": 1
    },
    { 
      "first_item": "A",
      "second_item": "A",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-11-02"),
      "quantity": 1
    },
    { 
      "first_item": "A",
      "second_item": "A",
      "third_item": "B",
      "price": 1,
      "sales_date": new Date("2018-10-31"),
      "quantity": 1
    },
    {
     "first_item": "A",
     "second_item": "A",
     "third_item": "B",
     "price": 1,
     "sales_date": new Date("2018-11-03"),
     "quantity": 1
    },
    {
      "first_item": "A",
      "second_item": "B",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-11-03"),
      "quantity": 1
     },
  ]
},
{
  "_id": 2,
  "data": [
    {
      "first_item": "A",
      "second_item": "A",
      "third_item": "A",
      "price": 2,
      "sales_date": new Date("2018-11-03"),
      "quantity": 1
    },
    { 
      "first_item": "A",
      "second_item": "A",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-10-31"),
      "quantity": 1
    },
    { 
      "first_item": "A",
      "second_item": "A",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-11-03"),
      "quantity": 1
    }
  ]
},
{
  "_id": 3,
  "data": [
    {
      "first_item": "A",
      "second_item": "B",
      "third_item": "A",
      "price": 1,
      "sales_date": new Date("2018-11-03"),
      "quantity": 1
     }
  ]
}

To te same dane, które pierwotnie pokazano, ale zamiast zagnieżdżania po prostu umieszczamy wszystko w pojedynczej spłaszczonej tablicy w każdym dokumencie nadrzędnym. Jasne, że oznacza to duplikację różnych punktów danych, ale różnica w złożoności i wydajności zapytania powinna być oczywista:

db.collection.aggregate([
  { "$match": {
    "data": {
      "$elemMatch": {
        "first_item": "A",
        "second_item": "A",
        "third_item": "A",
        "sales_date": {
          "$gte": new Date("2018-11-01"),
          "$lt": new Date("2018-12-01")
        }
      }
    }
  }},
  { "$addFields": {
    "data": {
      "$filter": {
        "input": "$data",
         "cond": {
           "$and": [
             { "$eq": [ "$$this.first_item", "A" ] },
             { "$eq": [ "$$this.second_item", "A" ] },
             { "$eq": [ "$$this.third_item", "A" ] },
             { "$gte": [ "$$this.sales_date", new Date("2018-11-01") ] },
             { "$lt": [ "$$this.sales_date", new Date("2018-12-01") ] }
           ]
         }
      }
    }
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": {
      "date": "$data.sales_date",
      "price": "$data.price",
    },
    "quantity_sold": { "$avg": "$data.quantity" }
  }},
  { "$group": {
    "_id": "$_id.date",
    "prices": {
      "$push": {
        "price": "$_id.price",
        "quantity_sold": "$quantity_sold"
      }
    },
    "quantity_sold": { "$avg": "$quantity_sold" }
  }}
])

Teraz zamiast zagnieżdżać te $elemMatch wywołania i podobnie dla $filter wyrażenia, wszystko jest znacznie jaśniejsze i łatwe do odczytania i naprawdę dość proste w przetwarzaniu. Inną zaletą jest to, że możesz nawet indeksować klucze elementów w tablicy, tak jak to zostało użyte w zapytaniu. To było ograniczenie zagnieżdżonego model, w którym MongoDB po prostu nie pozwala na takie "Indeksowanie wielokluczowe" na klawiszach tablic w tablicach . W przypadku pojedynczej tablicy jest to dozwolone i może być wykorzystane do poprawy wydajności.

Wszystko po „filtrowaniu zawartości tablicy” następnie pozostaje dokładnie taka sama, z wyjątkiem tylko nazw ścieżek, takich jak "data.sales_date" w przeciwieństwie do długiego "first_level.second_level.third_level.forth_level.sales_date" z poprzedniej struktury.

Kiedy NIE umieszczać

Wreszcie innym wielkim nieporozumieniem jest to, że WSZYSTKIE relacje należy przetłumaczyć jako osadzanie w tablicach. Tak naprawdę nigdy nie było to intencją MongoDB, a „powiązane” dane w tym samym dokumencie w tablicy można było przechowywać tylko w przypadku, gdy oznaczało to jednokrotne pobranie danych, a nie „łączenie”.

Klasyczny model „Zamówienie/Szczegóły” ma tutaj zwykle zastosowanie tam, gdzie we współczesnym świecie chcesz wyświetlić „nagłówek” dla „Zamówienia” ze szczegółami, takimi jak adres klienta, suma zamówienia itd. na tym samym „ekranu”, co szczegóły różne pozycje w „Zamówieniu”.

Dawno temu, w początkach RDBMS, typowy ekran 80 znaków na 25 wierszy miał po prostu takie informacje „nagłówka” na jednym ekranie, a szczegóły dotyczące wszystkiego, co kupiono, znajdowały się na innym ekranie. Więc naturalnie był pewien poziom zdrowego rozsądku, aby przechowywać je w osobnych tabelach. Gdy świat zaczął się bardziej szczegółowo przedstawiać na takich „ekranach”, zazwyczaj chcesz zobaczyć całość, a przynajmniej „nagłówek” i pierwsze tak wiele wierszy takiego „zamówienia”.

Dlatego tego rodzaju układ ma sens, aby umieścić go w tablicy, skoro MongoDB zwraca „dokument” zawierający wszystkie powiązane dane naraz. Nie ma potrzeby oddzielnych żądań dla oddzielnych renderowanych ekranów i nie ma potrzeby "dołączenia" takich danych, ponieważ są one już "wstępnie połączone".

Zastanów się, czy tego potrzebujesz – AKA „Pełna denormalizacja”

Tak więc w przypadkach, w których prawie wiesz, że przez większość czasu nie interesuje Cię radzenie sobie z większością danych w takich tablicach, ogólnie bardziej sensowne jest umieszczenie ich wszystkich w jednej kolekcji z zaledwie inną właściwością w w celu zidentyfikowania „rodzica” w przypadku, gdy takie „dołączenie” jest czasami wymagane:

{
  "_id": 1,
  "parent_id": 1,
  "first_item": "A",
  "second_item": "A",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-10-31"),
  "quantity": 1
},
{ 
  "_id": 2,
  "parent_id": 1,
  "first_item": "A",
  "second_item": "A",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-11-01"),
  "quantity": 1
},
{ 
  "_id": 3,
  "parent_id": 1,
  "first_item": "A",
  "second_item": "A",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-11-02"),
  "quantity": 1
},
{ 
  "_id": 4,
  "parent_id": 1,
  "first_item": "A",
  "second_item": "A",
  "third_item": "B",
  "price": 1,
  "sales_date": new Date("2018-10-31"),
  "quantity": 1
},
{
  "_id": 5,
  "parent_id": 1,
  "first_item": "A",
  "second_item": "A",
  "third_item": "B",
  "price": 1,
  "sales_date": new Date("2018-11-03"),
  "quantity": 1
},
{
  "_id": 6,
  "parent_id": 1,
  "first_item": "A",
  "second_item": "B",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-11-03"),
  "quantity": 1
},
{
  "_id": 7,
  "parent_id": 2,
  "first_item": "A",
  "second_item": "A",
  "third_item": "A",
  "price": 2,
  "sales_date": new Date("2018-11-03"),
  "quantity": 1
},
{ 
  "_id": 8,
  "parent_id": 2,
  "first_item": "A",
  "second_item": "A",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-10-31"),
  "quantity": 1
},
{ 
  "_id": 9,
  "parent_id": 2,
  "first_item": "A",
  "second_item": "A",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-11-03"),
  "quantity": 1
},
{
  "_id": 10,
  "parent_id": 3,
  "first_item": "A",
  "second_item": "B",
  "third_item": "A",
  "price": 1,
  "sales_date": new Date("2018-11-03"),
  "quantity": 1
}

Znowu są to te same dane, ale tym razem w całkowicie osobnych dokumentach z odniesieniem do rodzica w najlepszym przypadku, w przypadku, gdy faktycznie możesz ich potrzebować do innego celu. Zwróć uwagę, że agregacje w tym miejscu w ogóle nie odnoszą się do danych nadrzędnych i jasne jest również, gdzie dodatkowa wydajność i usunięta złożoność wchodzą w grę, po prostu przechowując je w oddzielnej kolekcji:

db.collection.aggregate([
  { "$match": {
    "first_item": "A",
    "second_item": "A",
    "third_item": "A",
    "sales_date": {
      "$gte": new Date("2018-11-01"),
      "$lt": new Date("2018-12-01")
    }
  }},
  { "$group": {
    "_id": {
      "date": "$sales_date",
      "price": "$price"
    },
    "quantity_sold": { "$avg": "$quantity" }
  }},
  { "$group": {
    "_id": "$_id.date",
    "prices": {
      "$push": {
        "price": "$_id.price",
        "quantity_sold": "$quantity_sold"
      }
    },
    "quantity_sold": { "$avg": "$quantity_sold" }
  }}
])

Ponieważ wszystko jest już dokumentem, nie ma potrzeby "filtrowania tablic" lub mają inną złożoność. Wszystko, co robisz, to wybieranie pasujących dokumentów i agregowanie wyników, z dokładnie tymi samymi dwoma ostatnimi krokami, które były obecne przez cały czas.

W celu osiągnięcia ostatecznych wyników, działa to znacznie lepiej niż którakolwiek z powyższych alternatyw. Zapytanie, o którym mowa, tak naprawdę dotyczy tylko danych „szczegółowych”, dlatego najlepszym sposobem działania jest całkowite oddzielenie szczegółów od elementu nadrzędnego, ponieważ zawsze zapewni to najlepszą wydajność.

A ogólnym punktem jest to, gdzie rzeczywisty wzorzec dostępu do reszty aplikacji NIGDY musi zwrócić całą zawartość tablicy, to prawdopodobnie i tak nie powinna być osadzona. Wydaje się, że większość operacji „zapisu” nie powinna i tak nigdy nie musieć dotykać powiązanego rodzica, a to kolejny decydujący czynnik, czy to działa, czy nie.

Wniosek

Ogólna wiadomość jest znowu taka, że ​​z reguły nigdy nie powinno się zagnieżdżać tablic. Co najwyżej powinieneś zachować "pojedynczą" tablicę z częściowo zdenormalizowanymi danymi w powiązanym dokumencie nadrzędnym, a tam, gdzie pozostałe wzorce dostępu naprawdę nie używają w ogóle rodzica i dziecka w parze, wtedy dane naprawdę powinny być rozdzielone.

„Duża” zmiana polega na tym, że wszystkie powody, dla których uważasz, że normalizacja danych jest rzeczywiście dobra, okazują się być wrogiem takich wbudowanych systemów dokumentów. Unikanie „połączeń” jest zawsze dobre, ale tworzenie złożonej struktury zagnieżdżonej, aby wyglądały na „połączone” dane, również nigdy nie działa na korzyść.

Koszt radzenia sobie z tym, co „myślisz”, że jest normalizacją, zwykle kończy się odstąpieniem od dodatkowego przechowywania i utrzymywania zduplikowanych i zdenormalizowanych danych w Twojej pamięci masowej.

Należy również zauważyć, że wszystkie powyższe formularze zwracają ten sam zestaw wyników. Jest to dość pochodna, ponieważ przykładowe dane dla zwięzłości obejmują tylko pojedyncze przedmioty lub co najwyżej w przypadku wielu punktów cenowych „średnia” nadal wynosi 1 bo takie są i tak wszystkie wartości. Ale treść wyjaśniająca to jest już niezmiernie długa, więc tak naprawdę jest to tylko „na przykład”:

{
        "_id" : ISODate("2018-11-01T00:00:00Z"),
        "prices" : [
                {
                        "price" : 1,
                        "quantity_sold" : 1
                }
        ],
        "quantity_sold" : 1
}
{
        "_id" : ISODate("2018-11-02T00:00:00Z"),
        "prices" : [
                {
                        "price" : 1,
                        "quantity_sold" : 1
                }
        ],
        "quantity_sold" : 1
}
{
        "_id" : ISODate("2018-11-03T00:00:00Z"),
        "prices" : [
                {
                        "price" : 1,
                        "quantity_sold" : 1
                },
                {
                        "price" : 2,
                        "quantity_sold" : 1
                }
        ],
        "quantity_sold" : 1
}



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. mongodb filtruje dokumenty z długością, szerokością geograficzną i określoną odległością

  2. MongoParseError:URI nie ma nazwy hosta, nazwy domeny i tld

  3. Używaj MongoEngine i PyMongo razem

  4. Indeksowanie Mongo na zagnieżdżonym obiekcie

  5. Jak używać wyrazistego mangusty, pomijać i ograniczać razem?