Chaves estrangeiras em mongo?


94

insira a descrição da imagem aqui

Como faço para projetar um esquema como este no MongoDB? Acho que não há chaves estrangeiras!


9
Você está pensando relacionalmente, em vez de orientado a documentos. : P
Pat

6
Por que você está usando o MongoDB se deseja um banco de dados relacional?
Adam Robinson

47
: D Estou tentando entender o método orientado a documentos; Como posso resolver essa tarefa?
Mark Pegasov

Se você quiser uma resposta para a maneira de pensar orientada a documentos, consulte stackoverflow.com/a/18637581/80428 . A resposta aceita atualmente funciona, mas é colocar o banco de dados relacional em um armazenamento de documentos que não é o objetivo do NoSQL.
Jay Wick

Respostas:


27

Você pode estar interessado em usar um ORM como Mongoid ou MongoMapper.

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

Em um banco de dados NoSQL como o MongoDB, não há 'tabelas', mas coleções. Os documentos são agrupados em Coleções. Você pode ter qualquer tipo de documento - com qualquer tipo de dados - em uma única coleção. Basicamente, em um banco de dados NoSQL, cabe a você decidir como organizar os dados e suas relações, se houver.

O que o Mongoid e o MongoMapper fazem é fornecer métodos convenientes para configurar relações com bastante facilidade. Confira o link que te dei e pergunte qualquer coisa.

Editar:

No mongoid, você escreverá seu esquema assim:

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

Editar:

> 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" }

Você pode usar esse ObjectId para fazer relações entre documentos.


Existem documentos com itens e quero vincular cidades. Criei coleção com cidades, mas não sei como vincular cidades com itens. PS, desculpe pelo meu péssimo inglês.
Mark Pegasov

UPD. Estou usando PHP como linguagem de programação, como posso usar o mongoid, se ele está escrito em Ruby?
Mark Pegasov

1
@ Жирайр Казаросян: Oh, entendo :) Ser um desenvolvedor Ruby me faz pensar apenas em Ruby :) Receio que não tenha experiência com PHP e Mongo, mas você pode verificar este link: mongodb.org/display/DOCS/ …
Nerian

1
@ Жирайр Казаросян: Aprendi Ruby on Rails com o livro Web development with Ruby on Rails, escrito por programadores pragmáticos. Você também pode obter uma introdução gratuita com este screencast codeschool.com/courses/rails-for-zombies
Nerian

2
Para leitores posteriores, as "tabelas" são "coleções" no MongoDB. Linhas são documentos e colunas são campos ... Para o caso de você se confundir.
cpu_meltdown

64

Como projetar uma mesa como essa no Mongodb?

Primeiro, para esclarecer algumas convenções de nomenclatura. MongoDB usa em collectionsvez de tables.

Acho que não há chaves estrangeiras!

Pegue o seguinte modelo:

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

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

Claramente, a lista de cursos de Jane aponta para alguns cursos específicos. O banco de dados não aplica nenhuma restrição ao sistema (por exemplo : restrições de chave estrangeira ), portanto, não há "exclusões em cascata" ou "atualizações em cascata". No entanto, o banco de dados contém as informações corretas.

Além disso, o MongoDB possui um padrão DBRef que ajuda a padronizar a criação dessas referências. Na verdade, se você der uma olhada nesse link, ele tem um exemplo semelhante.

Como posso resolver essa tarefa?

Para ser claro, o MongoDB não é relacional. Não existe uma "forma normal" padrão. Você deve modelar seu banco de dados de acordo com os dados armazenados e as consultas que pretende executar.


2
Ok, mas como posso obter os dados do nome de cortesia na coleção dos alunos? db.student.find () retornará algo como cursos: [{curso: 'bio101', marca: 85}]
Mark Pegasov

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

Do mongo doc sobre DBREF: "A menos que você tenha uma razão convincente para usar DBRefs, use referências manuais."
kroiz

22

Podemos definir o chamado foreign keyno MongoDB. No entanto, precisamos manter a integridade dos dados POR NÓS MESMOS . Por exemplo,

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

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

O coursescampo contém _ids de cursos. É fácil definir um relacionamento um para muitos. No entanto, se quisermos recuperar os nomes dos cursos do aluno Jane, precisamos realizar outra operação para recuperar o coursedocumento via _id.

Se o curso bio101for removido, precisamos realizar outra operação para atualizar o coursescampo no studentdocumento.

Mais: Projeto de esquema do MongoDB

A natureza do tipo de documento do MongoDB oferece suporte a maneiras flexíveis de definir relacionamentos. Para definir uma relação um-para-muitos:

Documento embutido

  1. Adequado para um-para-poucos.
  2. Vantagem: não há necessidade de realizar consultas adicionais a outro documento.
  3. Desvantagem: não é possível gerenciar a entidade de documentos embutidos individualmente.

Exemplo:

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

Referência infantil

Como o student/ courseexemplo acima.

Referência parental

Adequado para um para squillions, como mensagens de log.

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
}

Virtualmente, a hosté o pai de a logmsg. Fazer referência ao hostid economiza muito espaço, visto que as mensagens de log são quilhões.

Referências:

  1. 6 Regras Práticas para Projeto de Esquema MongoDB: Parte 1
  2. 6 Regras Práticas para Projeto de Esquema MongoDB: Parte 2
  3. 6 Regras Práticas para Projeto de Esquema MongoDB: Parte 3
  4. Modelar relacionamentos um-para-muitos com referências de documentos

19

Do livro The Little MongoDB

Outra alternativa ao uso de junções é desnormalizar seus dados. Historicamente, a desnormalização era reservada para códigos sensíveis ao desempenho ou quando os dados deveriam ser capturados (como em um log de auditoria). No entanto, com a popularidade cada vez maior do NoSQL, muitos dos quais não têm junções, a desnormalização como parte da modelagem normal está se tornando cada vez mais comum. Isso não significa que você deve duplicar todas as informações em todos os documentos. No entanto, em vez de permitir que o medo de dados duplicados direcione suas decisões de design, considere modelar seus dados com base em quais informações pertencem a qual documento.

Assim,

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

Se for um dado API RESTful, substitua o ID do curso por um link GET para o recurso do curso


Acho que essa é a resposta correta. A menos que você esteja armazenando dados relacionais no mongo, nesse caso, você realmente deveria ter se perguntado por que está usando o mongo.
Jay Wick

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.