Diseñar el esquema de datos

MongoDB Diseño del esquema

A la hora de diseñar el esquema hay que tener en cuenta algunas cosas:

Mongo soporta “rich documents” a diferencia de tablas planas.

  • Permite almacenar “Pre-joint /embebed data” para acelerar tiempos de acceso.
  • Mongo no soporta joints, ni constraints, ni definir un esquema rígido.
  • Realiza operaciones atómicas sobre un documento.

Lo más importante a tener en cuenta en el diseño del esquema, es que dicho esquema coincida con el patrón de acceso a los datos de nuestra aplicación.

En general, se va a tratar de evitar embeber documentos que puedan crear inconsistencias, por ejemplo, imaginemos un elemento [id, texto, usuario, correo]. Si modificamos el correo de un usuario, habría que modificar todos los registros donde aparezca el correo para no crear inconsistencias.

Pero por otro lado, si se crea una estructura de datos similar a como lo realizaríamos en el mundo relacional, probablemente no estemos aprovechando lo que ofrece Mongo, ya que tendríamos que hacer múltiples accesos a distintas colecciones. En general hay que tratar de embeber documentos en la medida de lo posible.

Vivir sin constraints 

Hay que asegurarse por código en el caso de que en una colección hagamos referencia a un id de otra colección, ya que en mongo db, en el momento de escribir este artículo, no existen constraints (se prevé que en un futuro si que exista algún mecanismo). Embeber los documentos es una solución a la referencia externa a una clave.

Vivir sin transacciones 

Lo mismo ocurre en el caso de las transacciones, ya que mongo no ofrece dicho mecanismo. En lugar de eso permite realizar operaciones atómicas en un documento de una colección, por lo que el diseño de éste debe ser delicado.

Relaciones uno a uno 

En las relaciones uno a uno, hay que determinar si merece la pena embeber un documento en otro o si por el contrario es mejor mantenerlos separados. Un ejemplo es una relación “delincuente” con su “historial delictivo” donde cualquiera de los dos documentos puede ir embebido en el otro. Hay que tener en cuenta una seria de cosas:

  • Frecuencia de acceso → ¿Siempre que se acceda al “historial delictivo” se va a acceder a los datos del delincuente, o esto ocurre rara vez?
  • Tamaño de los datos → ¿Cuánto está previsto que crezcan los datos? ¿Se mantendrán estables o crecerán a lo largo del tiempo? ¿Superarán el tamaño máximo de 16MB?
  • Atomicidad de las modificaciones → ¿Cómo y cuándo nos interesa modificar la información, de cara a evitar inconsistencias?
Relaciones uno a muchos (y uno a pocos) 

Un ejemplo de este tipo puede ser la relación ciudad y persona. Una ciudad puede tener muchas personas que vivan en ella. Una solución podría ser la siguiente:

{ nombre: Juan, profesión: Doctor, ciudad: {nombre: Madrid, provincia: Madrid}}

Esta solución no es adecuada, ya que los datos de la ciudad estarán repetidos muchas veces. Otra solución podría ser:

{nombre: Madrid, provincia: Madrid, ciudadanos: [  { juan…}, {pepe…} ]}

Esta solución tampoco es adecuada, ya que en ciudades como Madrid hay más de 3 millones de personas, lo que es demasiado. En este caso lo que habría que hacer es mantener dos colecciones y hacer referencia a la ciudad desde la colección persona.

En el caso de que sepamos que la relación “uno a muchos” es en realidad de “uno a pocos”, si que es adecuada esta solución, como en el caso de los comentarios de un blog, por ejemplo, que serán 4 ó 5.

Relaciones muchos a muchos

El caso típico puede ser el de médico y paciente, un médico tiene muchos pacientes y un paciente puede tener a varios médicos. En el caso de relaciones “pocos a pocos”, se puede embeber la información, aunque posiblemente no sea una buena idea. Quizas en este caso es mejor mantener dos colecciones y hacer la referencia a la otra, teniendo en cuenta que no hay integridad y tendríamos que asegurarla por código.

Multiíndices

El ejemplo de médico y paciente, podríamos encontrar los pacientes que tienen al médico 1 y 3 (siendo 1 y 3 el id de los médicos) de este modo:

db.paciente.ensureIndex({“medico”:1})

db.paciente.find({“medico”:{$all:[1,3]}})

La sentencia “ensureIndex()” crea un índice secundario que hace que la búsqueda sea muy rápida. Se usa un cursor en la propiedad médico.

Beneficios de embeber los documentos

El principal beneficio es la lectura rápida de información.

Árboles

La manera de representar relaciones jerárquicas, como una categoría o algo parecido, es definiendo los antecesores y los sucesores. Por ejemplo:

De  modo que si queremos saber todos los descendientes de la categoría “Pepe” lo haríamos del siguiente modo:

            db.categoria.find( {antepasados: 34}  )

Almacenar ficheros de más de 16Mb

Los ficheros se almacenan en Mongo usando GridFs. Lo que hace GridFs es utilizar dos colecciones, una para los metadatos y la otra para los trozos del blob.

Puedes saber más de esta utilidad consultando su api: http://api.mongodb.org/

Bueno, aquí terminamos con este artículo. En el próximo hablaremos sobre el rendimiento en MongoDB y los índices

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *