Внешние ключи в монго?

99

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

Как мне разработать такую ​​схему в MongoDB? Думаю внешних ключей нет!

Марк Пегасов
источник
10
Вы мыслите реляционно, а не ориентированно на документы. : P
Пэт
6
Почему вы используете MongoDB, если вам нужна реляционная база данных?
Адам Робинсон,
50
: D Я пытаюсь понять документально-ориентированный метод; Как я могу решить эту задачу?
Марк Пегасов
Если вам нужен ответ на документально-ориентированный образ мышления, см. Stackoverflow.com/a/18637581/80428 . Текущий принятый ответ работает, но переносит реляционную базу данных в хранилище документов, а NoSQL не о чем.
Джей Уик

Ответы:

27

Возможно, вам будет интересно использовать ORM, например Mongoid или MongoMapper.

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

В базе данных NoSQL, такой как MongoDB, есть не «таблицы», а коллекции. Документы сгруппированы внутри коллекций. У вас может быть любой документ - с любыми данными - в одной коллекции. По сути, в базе данных NoSQL вам решать, как организовать данные и их связи, если они есть.

Mongoid и MongoMapper предоставляют вам удобные методы для простой установки отношений. Просмотрите ссылку, которую я вам дал, и спросите о чем угодно.

Редактировать:

На монгоиде вы напишете свою схему так:

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 как язык программирования, как я могу использовать монгоид, если он написан на 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 02
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 () вернет что-то вроде курсов: [{course: 'bio101', mark: 85}]
Марк Пегасов
@ Жирайр Казаросян:> db.foo.find ({'_ id': ObjectId ("4df6539ae90592692ccc9940")}) -------------> {"_id": ObjectId ("4df6539ae90592692ccc9940"), "группа": "телефоны"}
Нериан
Из документа mongo о 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является родительским элементом для logmsg. Обращение к hostидентификатору экономит много места, учитывая, что сообщения журнала являются сквиллионами.

Ссылки:

  1. 6 практических правил проектирования схемы MongoDB: Часть 1
  2. 6 практических правил проектирования схемы MongoDB: часть 2
  3. 6 практических правил проектирования схемы MongoDB: часть 3
  4. Моделирование отношений "один ко многим" со ссылками на документы
Радость
источник
19

Из книги Little MongoDB

Еще одна альтернатива использованию объединений - денормализация ваших данных. Исторически денормализация была зарезервирована для кода, чувствительного к производительности, или когда данные должны быть сняты (например, в журнале аудита). Однако с постоянно растущей популярностью NoSQL, многие из которых не имеют соединений, денормализация как часть обычного моделирования становится все более распространенной. Это не означает, что вы должны дублировать каждую часть информации в каждом документе. Однако вместо того, чтобы позволить страху перед дублированием данных управлять вашими проектными решениями, подумайте о моделировании данных на основе того, какая информация принадлежит какому документу.

Так,

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

Если это данные RESTful API, замените идентификатор курса ссылкой GET на ресурс курса.

ZAky
источник
Думаю, это правильный ответ. Если вы не храните реляционные данные в mongo, и в этом случае вам действительно следовало бы спросить, почему вы используете mongo.
Джей Уик
0

Цель ForeignKey - предотвратить создание данных, если значение поля не соответствует его ForeignKey. Для этого в MongoDB мы используем промежуточное программное обеспечение Schema, которое обеспечивает согласованность данных.

Пожалуйста, посмотрите документацию. https://mongoosejs.com/docs/middleware.html#pre

Ахмет Эмребас
источник