¿Qué tipos de datos podemos utilizar en MongoDB?
Tipos de datos en MongoDB
¿Qué tipo de información podemos almacenar en una base de datos MongoDB? ¿Textos, números, arrays, ficheros multimedia,…? Vamos a ver qué tipos de datos podemos utilizar en MongoDB.
Documentos
En MongoDB la información se almacena en documentos, agrupados en colecciones que pertenecen a bases de datos. Ya vimos en un artículo anterior que los documentos de una colección no tienen porque compartir la misma estructura, aunque en general sí que lo harán. Pero no es obligatorio. Un ejemplo de documento podría ser:
nombre: "Juan"
apellidos: "Garcia Garcia"
edad: 28
aficiones: "Fútbol", "Ajedrez", "Surf"
Cómo veis un documento no es más que un conjunto de datos que representan una determinada información de un objeto. Por eso, en ocasiones cuando se habla de documentos en MongoDB, también se utiliza el término objeto. En este caso tenemos información de una persona.
En el ejemplo mostrado anteriormente hemos utilizado un determinado formato para representar cada una de las características de la persona. El nombre de la característica y su valor se separan con el símbolo «:», yendo primero el nombre de la característica. Utilizamos una línea para cada característica.
JSON
En MongoDB se utiliza otro formato para almacenar los documentos, BSON, que no es más que una extensión de JSON que se representa de manera binaria. JSON (JavaScript Object Notation) es un formato estándar utilizado principalmente para transmitir datos entre un servidor web y una aplicación web. Inicialmente extraído de JavaScript, actualmente es independiente del lenguaje de programación. En http://json.org/json-es.html tenemos la especificación de JSON.
JSON es de fácil lectura por parte de personas, al contrario que BSON. Sin embargo BSON acelera el acceso a la información contenida en un documento. Cuando trabajamos con la consola de MongoDB se utiliza JSON, ya que es más legible. Cuando trabajamos con los drivers del lenguaje que utilizamos para interactuar con MongoDB, se utiliza una estructura de dicho lenguaje parecida a JSON. En el caso de nodeJS es el propio JSON. En el caso de Java es una mapa DBObject. En Ruby es un Hash.
En cualquier caso, el driver es el encargado de convertir la información entre BSON y la estructura del lenguaje (JSON, DBObject, Hash,…). Cuando se lee de MongoDB se convierte de BSON a la estructura del lenguaje, y cuando se almacena en MongoDB al revés.
En JSON el formato es muy sencillo. Para cada característica tenemos un par nombre/valor, separados por el símbolo «:». El nombre es siempre una cadena o string, que identifica a cada uno de los pares. Los valores pueden ser de seis tipos:
-
String o cadena
-
Number o número
-
Boolean o booleano (true o false)
-
null
-
Array
-
Objeto o documento, es decir un objeto JSON puede contener otro documento JSON, sin límite de recursividad.
Los pares nombre/valor están separados por el símbolo «,». El conjunto está encerrado entre llaves ( { } ). Un ejemplo sería:
{
"edad": 17,
"nombre": "José",
"amigos": [ "Juan", "Ana", "Pedro" ],
"email": null,
"participaSorteo": true,
"preferencias": {
"seguimientoEmails": false,
"idioma": "Castellano",
"zonaHoraria": 1
}
}
En cada par nombre-valor, el nombre debe ir rodeado de comillas dobles, aunque la gran mayoría de lenguajes de programación admiten su no utilización, salvo que el nombre incluya espacios, puntos,… o empiece por algo que no sea una letra. Si bien el estándar no prohíbe explícitamente repetir el nombre para dos pares nombre-valor de un mismo documento JSON, debe evitarse siempre, puesto que en la práctica generalmente el segundo par oculta al primero.
BSON
Si MongoDB utilizase JSON para almacenar la información estaríamos limitados a seis tipos de datos, como acabamos de ver. Por ejemplo, no dispone de un tipo de datos específico para la fechas, aunque podemos utilizar una cadena de texto. Tampoco dispone de un tipo de datos para almacenar el contenido de un fichero.
BSON proporciona tipos de datos que no existen en JSON, como Date para fechas, BinData para información binaria, ObjectId para valores únicos (generalmente usado para el campo _id de las colecciones),… En http://bsonspec.org/#/specification tenéis la especificación, y en http://docs.mongodb.org/manual/reference/bson-types/ documentación de MongoDB al respecto.
Veamos algunos de los tipos de datos BSON:
-
ObjectId: es pequeño, casi único, rápido de crear y ordenado. Consta 12 bytes: cuatro para guardar los segundos desde el 1 de enero de 1970, tres para identificar la máquina, dos para identificar el proceso, y tres para un contador. Cuando se generan dos valores en el mismo segundo, en la misma máquina y desde el mismo proceso, el primero tendrá un valor aleatorio en el contador, y el segundo el anterior valor aleatorio más uno. Así que para que se repita el valor de ObjectId deben de generarse más de 16 millones y medio (2 elevado a 24) de valores en el mismo segundo, en la misma máquina y desde el mismo proceso. Se utiliza mucho como identificador de documentos, para diferenciar unívocamente unos de otros. En la consola para crear uno hacemos ObjectId().
-
Numéricos: enteros de 4 u 8 bytes, y reales de 8 bytes. Un valor numérico entero por defecto utiliza 4 bytes, mientras que un valor numérico real por defecto utiliza el tipo Double (tambien de 8 bytes). Para que un entero utilice 8 bytes hay que indicar explícitamente NumberLong().
-
String: utiliza UTF-8, lo que permite almacenar todo clase de caracteres internacionales. Cualquier valor encerrado entre comillas es por defecto un String.
-
Timestamp: consta de 64 bits. 32 para los segundos desde el 1 de enero de 1970 y 32 para un ordinal que distingue operaciones dentro de un mismo segundo.
-
UTC Datetime (Date en MongoDB): consta de 64 bits, que representan los milisegundos desde el 1 de enero de 1970. Los números negativos son fechas anteriores. Con esto tenemos un rango de unos 292 millones de años antes y después de la citada fecha. ¡No más efectos 2000! En la consola para utilizar el día y la hora actual podemos utilizar new Date() ó ISODate().
-
BinData: es un array de datos binarios que puede ser utilizado para guardar el contenido de ficheros, por ejemplo. Se suele utilizar con los drivers, no desde la consola de MongoDB.
En JSON no hay manera de representar estos nuevos tipos de datos que aporta BSON. Lo que hace MongoDB es extender JSON para que si se pueda hacer esto. Así cuando trabajamos con la consola por ejemplo, podemos utilizar datos de tipo fecha, ObjectId, BinData,… En el siguiente ejemplo, tenemos cómo se representan datos de tipo ObjectId y Date cuando exportamos información desde MongoDB:
{
"_id" : { "$oid" : "53172c1ea85874ad0f8f1c6e" },
"fecha" : { "$date" : 1394027550091 },
"cuenta" : 8,
"existe" : true,
"texto" : "Bla bla bla"
}
En el siguiente ejemplo, tenemos cómo se representan datos de tipo ObjectId y Date cuando los consultamos desde la consola de MongoDB:
{
"_id" : ObjectId("53172c1ea85874ad0f8f1ca4"),
"fecha" : ISODate("2014-03-05T13:52:30.038Z"),
"cuenta" : 8,
"existe" : true,
"texto" : "Bla bla bla"
}
Tenéis más ejemplos en la documentación de MongoDB al respecto, http://docs.mongodb.org/manual/reference/mongodb-extended-json/.
GridFS
En MongoDB, un documento BSON no puede ser superior a 16 MB. Así que independientemente del tipo de datos que estemos utilizando, para documentos grandes tenemos que utilizar GridFS, que básicamente lo que hace es dividir los documentos en trozos iguales (256 KBytes), y guardar cada uno de estos trozos en un documento.
Por ejemplo, imaginemos que queremos información de unos vídeos en MongoDB. En cada documento guardaremos el propio vídeo, más cierta información relacionada (fecha, modelo de cámara, ajustes de grabación,…) Lo normal es que algunos de los vídeos sean mayores de 16 MB, dependiendo de su calidad y duración, por lo que será necesario utilizar GridFS.
Conclusión
En MongoDB podemos utilizar los tipos de datos de JSON (cadena de texto, número, booleano, null, array y documento), más los que proporciona BSON (ObjectId, Date, BinData,…) Además si queremos guardar ficheros de más de 16 MB (vídeos por ejemplo) necesitaremos utilizar GridFS