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

Планиране и управление на схеми в MongoDB (дори въпреки че е безсхемно)

Когато беше представен MongoDB, основната подчертана характеристика беше способността му да бъде „безсхемен“. Какво означава? Това означава, че човек може да съхранява JSON документи, всеки с различна структура, в една и съща колекция. Това е доста готино. Но проблемът започва, когато трябва да извлечете документите. Как да разберете, че извлеченият документ е с определена структура или дали съдържа определено поле или не? Трябва да прегледате всички документи и да потърсите това конкретно поле. Ето защо е полезно внимателно да планирате схемата на MongoDB, особено за големите приложения.

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

Моделиране от един към няколко (вграждане)

Този дизайн е много добър пример за вграждане на документи. Разгледайте този пример за колекция Person, за да илюстрирате това моделиране.

{
  name: "Amy Cooper",
  hometown: "Seoul",
  addresses: [
    { city: 'New York', state: 'NY', cc: 'USA' },
    { city: 'Jersey City', state: 'NJ', cc: 'USA' }
  ]
}

Плюсове:

  • Можете да получите цялата информация с една заявка.

Минуси:

  • Вградените данни зависят изцяло от родителския документ. Не можете да търсите независимо вградените данни.
  • Помислете за примера, в който създавате система за проследяване на задачи, използвайки този подход. След това ще вградите всички задачи, специфични за един човек, в колекцията Person. Ако искате да задействате заявка като:Покажи ми всички задачи, които имат утре като краен срок. Това може да бъде много трудно, въпреки че е проста заявка. В този случай трябва да помислите за други подходи.

Моделиране едно към много (референтни)

При този тип моделиране родителският документ ще съдържа референтния идентификатор (ObjectID) на дъщерните документи. Трябва да използвате присъединявания на ниво приложение (комбиниране на два документа, след като ги извлечете от БД на ниво приложение), за да извлечете документи, така че няма обединения на ниво база данни. Следователно натоварването на базата данни ще бъде намалено. Помислете за този пример:

// Parts collection
{
  _id: ObjectID(1234),
  partno: '1',
  name: ‘Intel 100 Ghz CPU',
  qty: 100,
  cost: 1000,
  price: 1050
}
// Products collection
{
  name: 'Computer WQ-1020',
  manufacturer: 'ABC Company',
  catalog_number: 1234,
  parts: [
    ObjectID(‘1234’), <- Ref. for Part No: 1
    ObjectID('2345'),
    ObjectID('3456')
  ]
}

Да предположим, че всеки продукт може да има няколко хиляди части, свързани с него. За този вид база данни реферирането е идеалният тип моделиране. Поставяте референтните идентификатори на всички свързани части под продуктовия документ. След това можете да използвате присъединяване на ниво приложение, за да получите частите за конкретен продукт.

Плюсове:

  • При този тип моделиране всяка част е отделен документ, така че можете да приложите всички свързани с част заявки към тези документи. Няма нужда да зависи от родителския документ.
  • Много лесни за изпълнение CRUD (създаване, четене, актуализиране, запис) операции за всеки документ независимо.

Минуси:

  • Един основен недостатък на този метод е, че трябва да изпълните една допълнителна заявка, за да получите подробности за частта. За да можете да извършвате свързвания на ниво приложение с документа на продукта, за да получите необходимия набор от резултати. Така че може да доведе до спад в производителността на DB.
Severalnines Станете DBA на MongoDB – Пренасяне на MongoDB в Производството Научете какво трябва да знаете, за да внедрите, наблюдавате, управлявате и мащабирате MongoDB Изтеглете безплатно

Моделиране от един към милиони (препратка към родители)

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

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

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

// Machines collection
{
  _id : ObjectID('AAA'),
  name : 'mydb.example.com',
  ipaddr : '127.66.0.4'
}
// Logs collection
{
  time : ISODate("2015-09-02T09:10:09.032Z"),
  message : 'WARNING: CPU usage is critical!',
  host: ObjectID('AAA')       -> references Machine document
}

Да предположим, че искате да намерите най-новите 3000 журнала на машина 127.66.0.4:

machine = db.machines.findOne({ipaddr : '127.66.0.4'});
msgs = db.logmsg.find({machine: machine._id}).sort({time : -1}).limit(3000).toArray()

Двупосочна препратка

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

// person
{
  _id: ObjectID("AAAA"),
  name: "Bear",
  tasks [ 
    ObjectID("AAAD"),
    ObjectID("ABCD"), -> Reference of child document
    ObjectID("AAAB")
  ]
}
// tasks
{
  _id: ObjectID("ABCD"),
  description: "Read a Novel",
  due_date:  ISODate("2015-11-01"),
  owner: ObjectID("AAAA") -> Reference of parent document
}

Заключение

В крайна сметка всичко зависи от вашите изисквания за кандидатстване. Можете да проектирате схемата на MongoDB по начин, който е най-полезен за вашето приложение и ви осигурява висока производителност. Ето някои обобщени съображения, които можете да вземете предвид при проектирането на вашата схема.

  1. Проектирайте схемата въз основа на моделите за достъп до данни на вашето приложение.
  2. Не е необходимо да вграждате документи всеки път. Комбинирайте документи само ако ще ги използвате заедно.
  3. Помислете за дублиране на данни, защото съхранението е по-евтино от изчислителната мощност в днешно време.
  4. Оптимизиране на схемата за по-чести случаи на използване.
  5. Масивите не трябва да растат извън границите. Ако има повече от няколкостотин детски документа, не ги вграждайте.
  6. Предпочитайте свързвания на ниво приложение пред обединения на ниво база данни. С правилното индексиране и правилното използване на проекционните полета това може да ви спести много време.

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Създайте 2dsphere геопространствен индекс за сферични заявки в MongoDB

  2. MongoDB $isArray

  3. Сериализирайте един клас по два различни начина с Джаксън

  4. $skip и $limit в рамката за агрегиране

  5. Как да използвам Elasticsearch с MongoDB?