MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

MongoDB коментари за заявки заедно с потребителска информация

Проблемът(ите)

Както написано преди , има няколко проблема при прекомерно вграждане:

Проблем 1:Ограничение на размера на BSON

Към момента на писане, BSON документите са ограничени до 16 MB . Ако това ограничение бъде достигнато, MongoDB ще хвърли изключение и вие просто не можете да добавяте повече коментари и в най-лошия случай дори няма да промените (потребителското) име или картината, ако промяната би увеличила размера на документа.

Проблем 2:Ограничения на заявките и производителност

Не е лесно възможно да се направи запитване или сортиране на масива от коментари при определени условия. Някои неща биха изисквали доста скъпо агрегиране, други доста сложни изрази.

Въпреки че може да се спори, че след като заявките са налице, това не е особен проблем, моля да не се съглася. Първо, колкото по-сложна е заявката, толкова по-трудно е да се оптимизира както за разработчика, така и за оптимизатора на заявки на MongoDB. Постигнах най-добри резултати с опростяване на модели на данни и заявки, ускорявайки отговорите с фактор 100 в един случай.

При мащабиране ресурсите, необходими за сложни и/или скъпи заявки, може дори да се сумират до цели машини в сравнение с по-опростен модел на данни и съответни заявки.

Проблем 3:Поддържаемост

Не на последно място, може да се натъкнете на проблеми при поддържането на вашия код. Като просто правило

В този контекст „скъпо“ се отнася както за пари (за професионални проекти), така и за време (за хоби проекти).

(Моето!) Решение

Доста е лесно:опростете своя модел на данни. Следователно вашите заявки ще станат по-малко сложни и (надяваме се) по-бързи.

Стъпка 1:Определете вашите случаи на употреба

Това ще бъде странно предположение за мен, но важното тук е да ви покажа общия метод. Бих дефинирал вашите случаи на употреба, както следва:

  1. За дадена публикация потребителите трябва да могат да коментират
  2. За дадена публикация покажете автора и коментарите, заедно с потребителското име на коментиращите и авторите и тяхната снимка
  3. За даден потребител трябва да е възможно лесно да промени името, потребителското име и снимката

Стъпка 2:Моделирайте данните си по съответния начин

Потребители

Първо, имаме ясен потребителски модел

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

Тук няма нищо ново, добавено само за пълнота.

Публикации

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

И това е всичко за публикация. Има две неща, които трябва да се отбележат тук:първо, ние съхраняваме данните за автора, от които се нуждаем веднага, когато показваме публикация, тъй като това ни спестява заявка за много често срещан, ако не и повсеместен случай на употреба. Защо не запазваме съответно данните за коментарите и коментаторите? Поради ограничението за размер от 16 MB , ние се опитваме да предотвратим съхраняването на препратки в един документ. По-скоро съхраняваме препратките в документи за коментари:

Коментари

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

Както при публикациите, имаме всички необходими данни за показване на публикация.

Заявките

Това, което постигнахме сега, е, че заобиколихме ограничението за размер на BSON и не е необходимо да се позоваваме на потребителските данни, за да можем да показваме публикации и коментари, което трябва да ни спести много запитвания. Но да се върнем към случаите на употреба и още някои запитвания

Добавяне на коментар

Това вече е съвсем ясно.

Получаване на всички или някои коментари за дадена публикация

За всички коментари

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

За 3-те последни коментара

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

Така че за показване на публикация и всички (или някои) от нейните коментари, включително потребителските имена и снимки, имаме две заявки. Повече, отколкото ви трябваше преди, но ние заобиколихме ограничението за размер и по принцип можете да имате неограничен брой коментари за всяка публикация. Но нека да стигнем до нещо истинско

Получаване на последните 5 публикации и техните последни 3 коментара

Това е процес от две стъпки. Въпреки това, с правилно индексиране (ще се върнем към това по-късно) това все още трябва да бъде бързо (и следователно спестяване на ресурси):

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);
  }
)

Вземете всички публикации на даден потребител, сортирани от най-новите към най-старите и техните коментари

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});

Имайте предвид, че тук имаме само две заявки. Въпреки че трябва да направите "ръчно" връзката между публикациите и съответните им коментари, това трябва да е доста лесно.

Промяна на потребителско име

Това вероятно е изпълнен рядък случай на употреба. Въпреки това не е много сложно със споменатия модел на данни

Първо променяме потребителския документ

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

Прехвърляме старото потребителско име към съответния масив. Това е мярка за сигурност, в случай че нещо се обърка със следните операции. Освен това, ние задаваме проблемът за запис на доста високо ниво, за да сме сигурни, че данните са трайни.

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

Нищо особено тук. Изявлението за актуализация за коментарите изглежда почти същото. Въпреки че тези заявки отнемат известно време, те рядко се изпълняват.

Индексите

Като правило може да се каже, че MongoDB може да използва само един индекс на заявка. Въпреки че това не е съвсем вярно, тъй като има пресичания на индекси, лесно е да се справите с него. Друго нещо е, че отделните полета в съставния индекс могат да се използват независимо. Така че един лесен подход за оптимизиране на индекси е да се намери заявката с най-много полета, използвани в операции, които използват индекси, и да се създаде съставен индекс от тях. Имайте предвид, че редът на възникване в заявката има значение. И така, нека да продължим.

Публикации

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

Коментари

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

Заключение

Напълно вграденият документ за публикация е най-бързият начин за зареждането му и неговите коментари. Той обаче не се мащабира добре и поради естеството на евентуално сложни заявки, необходими за справяне с него, това предимство в производителността може да бъде използвано или дори елиминирано.

С горното решение търгувате известна скорост (ако!) срещу принципно неограничена мащабируемост и много по-прост начин за работа с данните.

Чт.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Python Mogo ImportError:не може да импортира име Connection

  2. Добавяне в Mongo DB и проблемът с идентификатора

  3. Намиране на обект въз основа на елемент от масив, връщане само на съответстващ елемент от масив?

  4. Фатална грешка:Класът „MongoDate“ не е намерен при използване на mongodb php драйвер 1.1.2 и PHP 7.0.2 - Laravel 5.1

  5. Сума на агрегиране в Spring Data MongoDB