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

Населяване на мангусти срещу гнездене на обекти

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

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

Частта „не вълшебна“ е, че по същество това, което се случва под кориците, е, че когато „препращате“ към друг източник, функцията за попълване прави допълнителна заявка/заявки към тази „свързана“ колекция, за да „слее“ тези резултати на родителя обект, който сте изтеглили. Можете да направите това сами, но методът е там за удобство, за да опрости задачата. Очевидното съображение за "производителност" е, че няма нито едно двупосочно пътуване до базата данни (екземпляр на MongoDB), за да се извлече цялата информация. Винаги има повече от един.

Като проба вземете две колекции:

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        ObjectId("5392fee10ff066b7d533a766"),
        ObjectId("5392fefe0ff066b7d533a767")
    ]
}

И елементите:

{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 }
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }

"Най-доброто", което може да бъде направено от "референтен" модел или използването на populate (под капака), е това:

var order = db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
order.items = db.items.find({ "_id": { "$in": order.items } ).toArray();

Така че очевидно има „поне“ две заявки и операции, за да се „присъединят“ към тези данни.

Концепцията за вграждане е по същество отговорът на MongoDB за това как да се справим с липсата на поддръжка на „съединявания“. Така че вместо да разделяте данните на нормализирани колекции, вие се опитвате да вградите „свързаните“ данни директно в документа, който ги използва. Предимствата тук са, че има една единствена операция "четене" за извличане на "свързаната" информация, както и една точка от операции "запис" за актуализиране както на "родителски", така и на "детски" записи, макар че често не е възможно да се пише на „много“ деца наведнъж, без да обработват „списъци“ на клиента или да приемат по друг начин „множествени“ операции за запис и за предпочитане при „партидна“ обработка.

Тогава данните изглеждат по-скоро така (в сравнение с примера по-горе):

{ 
    "_id": ObjectId("5392fea00ff066b7d533a765"),
    "customerName": "Bill",
    "items": [
        { "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 },
        { "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
    ]
}

Следователно действителното извличане на данните е само въпрос на:

db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });

Плюсовете и минусите на едното и другото винаги ще зависят до голяма степен от модела на използване на вашето приложение. Но с един поглед:

Вграждане

  • Общият размер на документа с вградени данни обикновено няма да надвишава 16MB памет (ограничението BSON) или по друг начин (като насока) има масиви, които съдържат 500 или повече записа.

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

  • Свързаните данни често се използват във връзка с родителя. Което означава, че ако вашите случаи на „четене/записване“ почти винаги се нуждаят от „четене/записване“ както на родител, така и на дете, тогава има смисъл да вградите данните за атомарни операции.

Препратка

  • Свързаните данни винаги ще надхвърлят ограничението от 16MB BSON. Винаги можете да помислите за хибриден подход на "кофа", но общият твърд лимит на основния документ не може да бъде нарушен. Често срещани случаи са „публикуване“ и „коментари“, при които се очаква активността на „коментари“ да бъде много голяма.

  • Свързаните данни се нуждаят от редовно актуализиране. Или по същество случаят, когато „нормализирате“, защото тези данни се „споделят“ между много родители и „свързаните“ данни се променят достатъчно често, че би било непрактично да се актуализират вградените елементи във всеки „родител“, където се появява този „дъщерен“ елемент . По-лесният случай е просто да посочите „дете“ и да направите промяната веднъж.

  • Има ясно разделение на четене и записване. В случай, когато може би няма да изисквате винаги тази „свързана“ информация, когато четете „родителя“ или по друг начин да не е необходимо винаги да променяте „родителя“, когато пишете на детето, може да има основателна причина да отделите модела както е посочено. Освен това, ако има общо желание да се актуализират много "поддокументи" наведнъж, в които тези "поддокументи" всъщност са препратки към друга колекция, тогава доста често реализацията е по-ефективна, когато данните са в отделна колекция колекция.

Така че всъщност има много по-широко обсъждане на "плюсите/против" за всяка позиция в документацията на MongoDB за моделиране на данни, която обхваща различни случаи на използване и начини за подход или чрез използване на вграждане или референтен модел, както се поддържа от метода за попълване.

Надяваме се, че „точковите точки“ са полезни, но като цяло препоръката е да вземете предвид моделите на използване на данни от вашето приложение и да изберете най-доброто. Наличието на „опция“ за вграждане „трябва“ да е причината да сте избрали MongoDB, но всъщност ще бъде как вашето приложение „използва данните“, което взема решението кой метод отговаря на коя част от вашето моделиране на данни (тъй като не е „всичко или нищо“) най-доброто.

  1. Обърнете внимание, че тъй като това е написано първоначално, MongoDB въведе $lookup оператор, който наистина извършва "съединяване" между колекции на сървъра. За целите на общата дискусия тук, в повечето случаи трябва да е "по-добре" от "множествената заявка", понесена от populate() и "множество заявки" като цяло, все още има "значителни допълнителни разходи" възникнали с всяко $lookup операция.

Основният принцип на проектиране е „вграден“ означава „вече там“, за разлика от „извличане от някъде другаде“. По същество разликата между „в джоба ви“ и „на рафта“ и в термини за I/O обикновено по-скоро като „на рафта в библиотеката в центъра“ , и особено по-далеч за мрежови заявки.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Намерете и пребройте елементи от колекция с Mongoose

  2. Проектиране на схема на база данни MongoDB

  3. ImportError:Няма модул с име objectid

  4. Mongorestore, от сървър за производство на метеор до локален

  5. Заявката Mongoose near(...) в индексирано поле на 2dsphere не връща валидни резултати