Зовнішні ключі в монго?


95

введіть тут опис зображення

Як мені розробити таку схему в MongoDB? Думаю, зовнішніх ключів немає!


9
Ви думаєте реляційно, а не орієнтовані на документи. : P
Пет

6
Чому ви використовуєте MongoDB, якщо хочете реляційну базу даних?
Адам Робінсон,

48
: D Я намагаюся зрозуміти документ-орієнтований метод; Як я можу вирішити це завдання?
Марк Пегасов

Якщо вам потрібна відповідь на орієнтований на документ спосіб мислення, див. Stackoverflow.com/a/18637581/80428 . Поточна прийнята відповідь працює, але є реляційною базою даних для зберігання документів, яка не стосується NoSQL.
Jay Wick

Відповіді:


27

Можливо, вам буде цікаво використовувати ORM, такий як Mongoid або MongoMapper.

http://mongoid.org/docs/relations/referenced/1-n.html

У базі даних NoSQL, як MongoDB, є не "таблиці", а колекції. Документи згруповані в колекціях. Ви можете мати будь-який документ - із будь-якими даними - в одній колекції. В основному, у базі даних NoSQL вам вирішувати, як упорядкувати дані та їх зв’язки, якщо вони є.

Те, що роблять Mongoid та MongoMapper, це надати вам зручні методи для встановлення відносин досить легко. Перевірте посилання, яке я вам дав, і запитайте щось.

Редагувати:

У mongoid ви напишете свою схему так:

class Student
  include Mongoid::Document

    field :name
    embeds_many :addresses
    embeds_many :scores    
end

class Address
  include Mongoid::Document

    field :address
    field :city
    field :state
    field :postalCode
    embedded_in :student
end

class Score
  include Mongoid::Document

    belongs_to :course
    field :grade, type: Float
    embedded_in :student
end


class Course
  include Mongoid::Document

  field :name
  has_many :scores  
end

Редагувати:

> db.foo.insert({group:"phones"})
> db.foo.find()                  
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }
{ "_id" : ObjectId("4df6540fe90592692ccc9941"), "group" : "phones" }
>db.foo.find({'_id':ObjectId("4df6539ae90592692ccc9940")}) 
{ "_id" : ObjectId("4df6539ae90592692ccc9940"), "group" : "phones" }

Ви можете використовувати цей ObjectId для встановлення відносин між документами.


Є документ із предметами, і я хочу пов’язати міста. Я створюю колекцію з містами, але не знаю, як пов’язати міста предметами. PS вибачте за мою погану англійську.
Марк Пегасов

UPD. Я використовую PHP як мову програмування, як я можу використовувати mongoid, якщо він написаний на Ruby?
Марк Пегасов

1
@ Жирайр Казаросян: О, я бачу :) Будучи розробником Ruby змушує мене думати лише на Ruby :) Я боюся, що у мене немає досвіду роботи з PHP та Mongo, але ви можете перевірити це посилання: mongodb.org/display/DOCS/ ...
Неріан,

1
@ Жирайр Казаросян: Я навчився Ruby on Rails за допомогою книги "Веб-розробка з Ruby on Rails" прагматичних програмістів. Ви також можете безкоштовно ознайомитись із цим скринкастом codechool.com/courses/rails-for-zombies
Неріан

2
Для подальших читачів "таблиці" - це "колекції" в MongoDB. Рядки - це документи, а стовпці - поля ... Про всяк випадок, якщо ви змішаєтесь.
cpu_meltdown

65

Як оформити такий стіл у mongodb?

По-перше, для уточнення деяких конвенцій щодо іменування. MongoDB використовує collectionsзамість tables.

Думаю, зовнішніх ключів немає!

Візьмемо таку модель:

student
{ 
  _id: ObjectId(...),
  name: 'Jane',
  courses: [
    { course: 'bio101', mark: 85 },
    { course: 'chem101', mark: 89 }
  ]
}

course
{
  _id: 'bio101',
  name: 'Biology 101',
  description: 'Introduction to biology'
}

Очевидно, що список курсів Джейн вказує на деякі конкретні курси. База даних не застосовує жодних обмежень до системи ( тобто: обмеження зовнішнього ключа ), тому не існує "каскадного видалення" або "каскадного оновлення". Однак база даних містить правильну інформацію.

Крім того, MongoDB має стандарт DBRef, який допомагає стандартизувати створення цих посилань. Насправді, якщо ви подивитесь на це посилання, воно має подібний приклад.

Як я можу вирішити це завдання?

Щоб бути зрозумілим, MongoDB не є реляційним. Стандартної "нормальної форми" не існує. Ви повинні змоделювати свою базу даних відповідно до даних, які ви зберігаєте, і запитів, які ви збираєтеся виконати.


2
Гаразд, але як я можу отримати дані про назви курсів із колекції студентів? db.student.find () поверне щось на зразок курсів: [{курс: 'bio101', позначка: 85}]
Марк Пегасов

@ Жирайр Казаросян:> db.foo.find ({'_ id': ObjectId ("4df6539ae90592692ccc9940")}) -------------> {"_id": ObjectId ("4df6539ae90592692ccc9940"), "group": "phones"}
Неріан,

З монго-документа про DBREF: "Якщо у вас немає вагомих причин використовувати DBRef, використовуйте замість них посилання вручну."
kroiz

23

Ми можемо визначити так званий foreign keyв MongoDB. Однак нам потрібно підтримувати цілісність даних САМИМИ . Наприклад,

student
{ 
  _id: ObjectId(...),
  name: 'Jane',
  courses: ['bio101', 'bio102']   // <= ids of the courses
}

course
{
  _id: 'bio101',
  name: 'Biology 101',
  description: 'Introduction to biology'
}

coursesПоле містить _idе курси. Легко визначити стосунки один до багатьох. Однак, якщо ми хочемо отримати імена курсів студента Jane, нам потрібно виконати ще одну операцію для отримання courseдокумента за допомогою _id.

Якщо курс bio101видалено, нам потрібно виконати ще одну операцію з оновлення coursesполя в studentдокументі.

Більше: Схема проектування MongoDB

Характер MongoDB, оформлений документом, підтримує гнучкі способи визначення взаємозв’язків. Щоб визначити взаємозв'язок "один до багатьох":

Вбудований документ

  1. Підходить для кількох.
  2. Перевага: немає необхідності виконувати додаткові запити до іншого документа.
  3. Недолік: неможливо керувати об’єктом вбудованих документів окремо.

Приклад:

student
{
  name: 'Kate Monster',
  addresses : [
     { street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
     { street: '123 Avenue Q', city: 'New York', cc: 'USA' }
  ]
}

Посилання на дітей

Як у прикладі student/ courseвище.

Посилання батьків

Підходить для некваліфікованих мільйонів, таких як повідомлення журналу.

host
{
    _id : ObjectID('AAAB'),
    name : 'goofy.example.com',
    ipaddr : '127.66.66.66'
}

logmsg
{
    time : ISODate("2014-03-28T09:42:41.382Z"),
    message : 'cpu is on fire!',
    host: ObjectID('AAAB')       // Reference to the Host document
}

Практично a hostє батьком a logmsg. Посилання на hostідентифікатор економить багато місця, враховуючи те, що повідомлення журналу є мільйонами.

Список літератури:

  1. 6 правил використання великого пальця для проектування схеми MongoDB: Частина 1
  2. 6 Правил використання великого пальця для проектування схеми MongoDB: Частина 2
  3. 6 Правил використання великого пальця для проектування схеми MongoDB: Частина 3
  4. Моделюйте взаємозв'язки "один із багатьма" за допомогою посилань на документи

19

З «Маленької книги МонгоДБ»

Ще однією альтернативою використання об’єднань є денормалізація даних. Історично денормалізація була зарезервована для коду, що чутливий до продуктивності, або коли дані повинні бути зроблені моментальними знімками (як у журналі аудиту). Однак із постійно зростаючою популярністю NoSQL, багато з яких не мають об’єднань, денормалізація як частина звичайного моделювання стає все більш поширеною. Це не означає, що ви повинні дублювати кожну інформацію в кожному документі. Однак замість того, щоб боятися дублікатів даних керувати вашими дизайнерськими рішеннями, подумайте про моделювання даних на основі того, яка інформація належить до якого документа.

Так,

student
{ 
    _id: ObjectId(...),
    name: 'Jane',
    courses: [
    { 
        name: 'Biology 101', 
        mark: 85, 
        id:bio101 
    },
  ]
}

Якщо це дані RESTful API, замініть ідентифікатор курсу на посилання GET на ресурс курсу


Я думаю, це правильна відповідь. Якщо ви не зберігаєте реляційні дані в mongo, у такому випадку ви справді мали б поставити під сумнів, чому ви використовуєте mongo.
Jay Wick

0

Метою ForeignKey є запобігання створенню даних, якщо значення поля не відповідає його ForeignKey. Для досягнення цього в MongoDB ми використовуємо проміжні засоби схеми, які забезпечують узгодженість даних.

Будь ласка, подивіться документацію. https://mongoosejs.com/docs/middleware.html#pre

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.