¿Claves extranjeras en mongo?

96

ingrese la descripción de la imagen aquí

¿Cómo diseño un esquema como este en MongoDB? ¡Creo que no hay claves foráneas!

Mark Pegasov
fuente
9
Estás pensando de forma relacional, en lugar de orientada a documentos. : P
Pat
6
¿Por qué utiliza MongoDB si desea una base de datos relacional?
Adam Robinson
48
: D Estoy tratando de entender el método orientado a documentos; ¿Cómo puedo solucionar esta tarea?
Mark Pegasov
Si desea la respuesta a la forma de pensar orientada a documentos, consulte stackoverflow.com/a/18637581/80428 . La respuesta aceptada actual funciona, pero es la base de datos relacional de calzador a un almacén de documentos que no es de lo que se trata NoSQL.
Jay Wick

Respuestas:

27

Puede que le interese utilizar un ORM como Mongoid o MongoMapper.

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

En una base de datos NoSQL como MongoDB no hay 'tablas' sino colecciones. Los documentos se agrupan dentro de Colecciones. Puede tener cualquier tipo de documento, con cualquier tipo de datos, en una sola colección. Básicamente, en una base de datos NoSQL depende de usted decidir cómo organizar los datos y sus relaciones, si las hay.

Lo que hacen Mongoid y MongoMapper es proporcionarle métodos convenientes para establecer relaciones con bastante facilidad. Mira el enlace que te di y pregunta cualquier cosa.

Editar:

En mongoid escribirás tu esquema así:

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

Puede usar ese ObjectId para hacer relaciones entre documentos.

Nerian
fuente
Hay documentos con elementos y quiero unir ciudades. He creado una colección con ciudades, pero no sé cómo unir ciudades con elementos. PD: lo siento por mi mal inglés.
Mark Pegasov
UPD. Estoy usando PHP como lenguaje de programación, ¿cómo puedo usar mongoid, si está escrito en Ruby?
Mark Pegasov
1
@ Жирайр Казаросян: Oh, ya veo :) Ser un desarrollador de Ruby me hace pensar solo en Ruby :) Me temo que no tengo experiencia con PHP y Mongo, pero puedes consultar este enlace: mongodb.org/display/DOCS/ …
Nerian
1
@ Жирайр Казаросян: Aprendí Ruby on Rails con el libro Desarrollo web con Ruby on Rails, de los programadores pragmáticos. También puede obtener una introducción gratis con este screencast codeschool.com/courses/rails-for-zombies
Nerian
2
Para lectores posteriores, las "tablas" son "colecciones" en MongoDB. Las filas son documentos y las columnas son campos ... Por si acaso se confunden.
cpu_meltdown
65

¿Cómo diseñar una mesa como esta en mongodb?

Primero, para aclarar algunas convenciones de nomenclatura. MongoDB usa en collectionslugar de tables.

¡Creo que no hay claves foráneas!

Toma el siguiente 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, la lista de cursos de Jane apunta a algunos cursos específicos. La base de datos no aplica ninguna restricción al sistema ( es decir, restricciones de clave externa ), por lo que no hay "eliminaciones en cascada" o "actualizaciones en cascada". Sin embargo, la base de datos contiene la información correcta.

Además, MongoDB tiene un estándar DBRef que ayuda a estandarizar la creación de estas referencias. De hecho, si echa un vistazo a ese enlace, tiene un ejemplo similar.

¿Cómo puedo solucionar esta tarea?

Para ser claros, MongoDB no es relacional. No existe una "forma normal" estándar. Debe modelar su base de datos de manera apropiada para los datos que almacena y las consultas que pretende ejecutar.

Vicepresidente de Gates
fuente
2
Bien, pero ¿cómo puedo obtener los datos del nombre de la fuente de la colección de estudiantes? db.student.find () devolverá algo como cursos: [{curso: 'bio101', marca: 85}]
Mark Pegasov
@ Жирайр Казаросян:> db.foo.find ({'_ id': ObjectId ("4df6539ae90592692ccc9940")}) -------------> {"_id": ObjectId ("4df6539ae90592692ccc9940"), "group": "phones"}
Nerian
De mongo doc sobre DBREF: "A menos que tenga una razón convincente para usar DBRefs, use referencias manuales en su lugar".
kroiz
23

Podemos definir el llamado foreign keyen MongoDB. Sin embargo, necesitamos mantener la integridad de los datos POR NOSOTROS MISMOS . Por ejemplo,

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

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

El coursescampo contiene _ids de cursos. Es fácil definir una relación de uno a varios. Sin embargo, si queremos recuperar los nombres de los estudiantes del curso Jane, necesitamos realizar otra operación para recuperar el coursedocumento a través de _id.

Si bio101se elimina el curso , debemos realizar otra operación para actualizar el coursescampo en el studentdocumento.

Más: MongoDB Schema Design

La naturaleza de tipo documento de MongoDB admite formas flexibles de definir relaciones. Para definir una relación de uno a varios:

Documento incrustado

  1. Adecuado para unos pocos.
  2. Ventaja: no es necesario realizar consultas adicionales a otro documento.
  3. Desventaja: no se puede gestionar la entidad de documentos incrustados individualmente.

Ejemplo:

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

Referencia infantil

Como el student/ courseejemplo anterior.

Referencia de padres

Adecuado para uno a escuillones, como mensajes de registro.

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
}

Prácticamente, a hostes el padre de a logmsg. Hacer referencia a la hostidentificación ahorra mucho espacio dado que los mensajes de registro son millones.

Referencias:

  1. 6 reglas generales para el diseño de esquemas de MongoDB: Parte 1
  2. 6 reglas generales para el diseño de esquemas de MongoDB: Parte 2
  3. 6 reglas generales para el diseño de esquemas de MongoDB: Parte 3
  4. Modelar relaciones de uno a varios con referencias de documentos
Alegría
fuente
19

Del libro Little MongoDB

Sin embargo, otra alternativa al uso de combinaciones es desnormalizar sus datos. Históricamente, la desnormalización se reservaba para el código sensible al rendimiento o cuando los datos debían tomarse una instantánea (como en un registro de auditoría). Sin embargo, con la creciente popularidad de NoSQL, muchos de los cuales no tienen combinaciones, la desnormalización como parte del modelado normal se está volviendo cada vez más común. Esto no significa que deba duplicar todos los datos de cada documento. Sin embargo, en lugar de dejar que el miedo a los datos duplicados impulse sus decisiones de diseño, considere modelar sus datos en función de qué información pertenece a qué documento.

Entonces,

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

Si se trata de datos de la API RESTful, reemplace la identificación del curso con un enlace GET al recurso del curso

ZAky
fuente
Creo que esta es la respuesta correcta. A menos que esté almacenando datos relacionales en mongo, en cuyo caso, debería haberse preguntado por qué está usando mongo.
Jay Wick
0

El propósito de ForeignKey es evitar la creación de datos si el valor del campo no coincide con su ForeignKey. Para lograr esto en MongoDB, usamos middlewares Schema que aseguran la consistencia de los datos.

Consulte la documentación. https://mongoosejs.com/docs/middleware.html#pre

Ahmet Emrebas
fuente