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

Komentarze do zapytań MongoDB wraz z informacjami o użytkowniku

Problem(y)

Jak napisane wcześniej , istnieje kilka problemów z nadmiernym osadzaniem:

Problem 1:Limit rozmiaru BSON

W chwili pisania tego tekstu Dokumenty BSON są ograniczone do 16 MB . Jeśli ten limit zostanie osiągnięty, MongoDB zgłosi wyjątek i po prostu nie będziesz mógł dodać więcej komentarzy, aw najgorszym przypadku nawet nie zmienisz nazwy (użytkownika) ani obrazu, jeśli zmiana zwiększyłaby rozmiar dokumentu.

Problem 2:Ograniczenia i wydajność zapytań

Pod pewnymi warunkami nie jest łatwo wykonać zapytanie lub posortować tablicę komentarzy. Niektóre rzeczy wymagałyby dość kosztownej agregacji, inne raczej skomplikowanych instrukcji.

Chociaż można argumentować, że gdy zapytania są już na miejscu, nie stanowi to większego problemu, błagam o różnicę. Po pierwsze, im bardziej skomplikowane jest zapytanie, tym trudniej jest je zoptymalizować, zarówno dla dewelopera, jak i później optymalizatora zapytań MongoDBs. Osiągnąłem najlepsze wyniki z uproszczeniem modeli danych i zapytań, przyspieszeniem odpowiedzi o współczynnik 100 w jednym przypadku.

Podczas skalowania zasoby potrzebne do skomplikowanych i/lub kosztownych zapytań mogą nawet sumować się na całe maszyny w porównaniu z prostszym modelem danych i odpowiednimi zapytaniami.

Problem 3:Utrzymanie

Na koniec możesz napotkać problemy z utrzymaniem kodu. Prosta zasada

W tym kontekście „drogie” odnosi się zarówno do pieniędzy (w przypadku projektów profesjonalnych), jak i czasu (w przypadku projektów hobbystycznych).

(Moje!) Rozwiązanie

To całkiem proste:uprość swój model danych. W rezultacie Twoje zapytania staną się mniej skomplikowane i (miejmy nadzieję) szybsze.

Krok 1:Zidentyfikuj swoje przypadki użycia

To będzie dla mnie szalone przypuszczenie, ale ważne jest, aby pokazać ogólną metodę. Zdefiniowałbym twoje przypadki użycia w następujący sposób:

  1. Dla danego posta użytkownicy powinni mieć możliwość komentowania
  2. Dla danego posta pokaż autora i komentarze, wraz z komentującymi i nazwą użytkownika autora oraz ich zdjęciem
  3. Dla danego użytkownika powinna być łatwo możliwa zmiana nazwy, nazwy użytkownika i zdjęcia

Krok 2:odpowiednio modeluj swoje dane

Użytkownicy

Przede wszystkim mamy prosty model użytkownika

{
  _id: new ObjectId(),
  name: "Joe Average",
  username: "HotGrrrl96",
  picture: "some_link"
}

Nie ma tu nic nowego, dodane tylko dla kompletności.

Posty

{
  _id: new ObjectId()
  title: "A post",
  content: " Interesting stuff",
  picture: "some_link",
  created: new ISODate(),
  author: {
    username: "HotGrrrl96",
    picture: "some_link"
  }
}

I o to chodzi w poście. Należy zwrócić uwagę na dwie rzeczy:po pierwsze, przechowujemy dane autora, których potrzebujemy natychmiast podczas wyświetlania posta, ponieważ oszczędza nam to zapytania o bardzo powszechny, jeśli nie wszechobecny przypadek użycia. Dlaczego nie zapisujemy odpowiednio komentarzy i danych komentatorów? Ze względu na limit 16 MB , staramy się zapobiec przechowywaniu referencji w jednym dokumencie. Zamiast tego przechowujemy odniesienia w dokumentach komentarzy:

Komentarze

{
  _id: new ObjectId(),
  post: someObjectId,
  created: new ISODate(),
  commenter: {
    username: "FooBar",
    picture: "some_link"
  },
  comment: "Awesome!"
}

Podobnie jak w przypadku postów, mamy wszystkie niezbędne dane do wyświetlenia posta.

Zapytania

To, co osiągnęliśmy teraz, to ominięcie limitu rozmiaru BSON i nie musimy odwoływać się do danych użytkownika, aby móc wyświetlać posty i komentarze, co powinno oszczędzić nam wielu zapytań. Wróćmy jednak do przypadków użycia i kilku innych zapytań

Dodawanie komentarza

Teraz jest to całkowicie proste.

Pobieranie wszystkich lub niektórych komentarzy do danego posta

Dla wszystkich komentarzy

db.comments.find({post:objectIdOfPost})

3 ostatnie komentarze

db.comments.find({post:objectIdOfPost}).sort({created:-1}).limit(3)

Tak więc za wyświetlanie postu i wszystkich (lub niektórych) jego komentarzy, w tym nazw użytkowników i zdjęć, jesteśmy na dwa pytania. Więcej niż potrzebowałeś wcześniej, ale obeszliśmy limit rozmiaru i w zasadzie możesz mieć nieskończoną liczbę komentarzy do każdego posta. Ale przejdźmy do czegoś prawdziwego

Pobieranie ostatnich 5 postów i ich 3 ostatnie komentarze

Jest to proces dwuetapowy. Jednak przy odpowiednim indeksowaniu (wrócimy do tego później) nadal powinno to być szybkie (a tym samym oszczędzać zasoby):

var posts = db.posts.find().sort({created:-1}).limit(5)
posts.forEach(
  function(post) {
    doSomethingWith(post);
    var comments = db.comments.find({"post":post._id}).sort("created":-1).limit(3);
    doSomethingElseWith(comments);
  }
)

Pobierz wszystkie posty danego użytkownika posortowane od najnowszych do najstarszych i ich komentarze

var posts = db.posts.find({"author.username": "HotGrrrl96"},{_id:1}).sort({"created":-1});
var postIds = [];
posts.forEach(
  function(post){
    postIds.push(post._id);
  }
)
var comments = db.comments.find({post: {$in: postIds}}).sort({post:1, created:-1});

Zauważ, że mamy tu tylko dwa zapytania. Chociaż musisz „ręcznie” nawiązać połączenie między postami i ich komentarzami, powinno to być całkiem proste.

Zmień nazwę użytkownika

Przypuszczalnie jest to rzadki przypadek użycia. Jednak nie jest to zbyt skomplikowane w przypadku wspomnianego modelu danych

Najpierw zmieniamy dokument użytkownika

db.users.update(
  { username: "HotGrrrl96"},
  {
    $set: { username: "Joe Cool"},
    $push: {oldUsernames: "HotGrrrl96" }
  },
  {
    writeConcern: {w: "majority"}
  }
);

Wstawiamy starą nazwę użytkownika do odpowiedniej tablicy. Jest to środek bezpieczeństwa na wypadek, gdyby coś poszło nie tak z następującymi operacjami. Ponadto ustawiliśmy problem zapisu na dość wysokim poziomie, aby upewnić się, że dane są trwałe.

db.posts.update(
  { "author.username": "HotGrrrl96"},
  { $set:{ "author.username": "Joe Cool"} },
  {
    multi:true,
    writeConcern: {w:"majority"}
  }
)

Nic specjalnego tutaj. Oświadczenie o aktualizacji komentarzy wygląda prawie tak samo. Chociaż te zapytania zajmują trochę czasu, rzadko są wykonywane.

Indeksy

Z reguły można powiedzieć, że MongoDB może używać tylko jednego indeksu na zapytanie. Chociaż nie jest to do końca prawdą, ponieważ istnieją przecięcia indeksów, łatwo sobie z tym poradzić. Inną rzeczą jest to, że poszczególne pola w indeksie złożonym mogą być używane niezależnie. Tak więc łatwym podejściem do optymalizacji indeksów jest znalezienie zapytania z największą liczbą pól używanych w operacjach wykorzystujących indeksy i utworzenie z nich indeksu złożonego. Zwróć uwagę, że kolejność występowania w zapytaniu ma znaczenie. Więc chodźmy dalej.

Posty

db.posts.createIndex({"author.username":1,"created":-1})

Komentarze

db.comments.createIndex({"post":1, "created":-1})

Wniosek

W pełni osadzony dokument na post jest wprawdzie najszybszym sposobem jego załadowania i komentarzy. Jednak nie skaluje się dobrze, a ze względu na charakter potencjalnie złożonych zapytań niezbędnych do poradzenia sobie z nim, ta przewaga wydajności może zostać wykorzystana, a nawet wyeliminowana.

Dzięki powyższemu rozwiązaniu handlujesz pewną szybkością (jeśli!) z zasadniczo nieograniczoną skalowalnością i znacznie prostszym sposobem radzenia sobie z danymi.

H.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Uzyskaj liczbę poziomów logowania dla każdej nazwy

  2. Odległość geograficzna MongoDB/promień do użytecznych jednostek

  3. Zagnieżdżona struktura zapytania mongodb

  4. Jak zaktualizować konkretny element tablicy w MongoDB

  5. Jak korzystać z MongoRegex (sterownik MongoDB C#)