Tipos

Tabla de contenidos

MongoDB permite a los programadores guardar y consultar datos expresados tanto en los tipos básicos de PHP, los tipos compuestos (arrays, arrays asociativos, y objetos), y en media docena de clases que proporciona el driver MongoDB de PHP (para expresiones regulares, fechas, y otras aplicaciones especializadas).

Booleanos y NULL

TRUE, FALSE, y NULL pueden usarse tal cual.

Números

En MongoDB los números son distintos de los strings: "123" no es lo mismo que 123. Por tanto, si se desea asegurar de que los números se ordenan y comparan correctamente, debe asegurarse de que realmente se almacenan como números.

<?php

$doc 
= array("a" => 123"b" => "123");
$collection->insert($doc);

$doc->find(array("a" => 123));   // coincide
$doc->find(array("a" => "123")); // no coincide
$doc->find(array("a" => 123.0)); // coincide
$doc->find(array("b" => 123));   // no coincide
$doc->find(array("b" => "123")); // coincide

?>

Como vemos, los números en coma flotante se comparan y coinciden con los números enteros tal como cabría esperar.

Números Largos

Por omisión, en sistemas de 32 bits, los números se envían a la base de datos como enteros de 32 bit. En sistemas 64 bits, se envían como enteros de 64 bit. Para guardar la compatibilidad, todos los sistemas deserializan los enteros de 64 bit como números en coma flotante. Los números en coma flotante no son exactos. Si fuera necesario usar valores exactos, habría que hacerlo ajsutando el fichero php.ini.

En sistemas de 32 bits, si mongo.long_as_object está habilitado, los enteros de 64 bit se devolverán como objetos MongoInt64. El entero se almacenará en el campo value con una precisión perfecta (como un string). MongoInt64 puede usarse también para guardar enteros de 64 bit en máquinas de 32 bits.

En sistemas de 64 bits, puede o bien habilitarse mongo.long_as_object o mongo.native_long. mongo.native_long devolverá enteros de 64 bit y enteros "normales" de PHP. MongoInt32 puede usarse para almacenar enteros de 32 bit en máquinas de 64 bits.

Debe establecerse un valor en mongo.long_as_object y en mongo.native_long de acuerdo al comportamiento que se espere, incluso en el caso de que coincida con los valores por omisión (para prevenir futuros cambios de estos valores).

Vea también: Opciones de php.ini, MongoInt32, MongoInt64.

Strings

Los strings deben ser UTF-8. Si no, o bien se convierten a UTF-8 antes de enviarse a la base de datos, o bien se almacenan como datos binarios.

Pueden usarse expresiones regulares para consultar strings, y se expresan usando la clase MongoRegex.

Datos Binarios

Tanto los textos que no son UTF-8, como las imágenes, o cualuier otro dato binario, debe enviarse a la base de datos usando el tipo MongoBinData.

Fechas

Pueden crearse fechas usando la clase MongoDate. Se almacenan como milisegundos a partir de la fecha de referencia.

MongoTimestamp no es para almacenar fechas ni timestamps, sino que se usa internamente por MongoDB. A no ser que se esté creando una herramienta que interactúe con los entresijos de réplicas o sharding, se deberá usar MongoDate, y no MongoTimestamp.

Ids Únicos

El driver creará automáticamente un campo _id antes de insertar un documento (a no ser que el usuario haya especificado uno). Este campo es una instancia de MongoId (en otros lenguajes habitualmente se le llama "ObjectId").

Estos ids se componen de 12 bytes:

  • 4 bytes de timestamp

    Dos registros no pueden tener el mismo id si se han insertado en momentos diferentes.

  • 3 bytes de id de máquina

    Dos registros no pueden tener el mismo id si se han insertado en máquinas diferentes.

  • 2 bytes de id de hebra

    Dos registros no pueden tener el mismo id si se han insertado por diferentes hebras en la misma máquina.

  • 3 bytes de valor incremental

    Cada vez que se crea un id, un contador global se incrementa, y se usa para el incremento del siguiente id.

Por tanto, dos registros no pueden tener el mismo id, a no ser que un único proceso en una misma máquina trate de insertar 256^3 (más de 16 millones) de documentos en un segundo, desbordando el campo de incremento.

JavaScript

MongoDB incorpora un motor JavaScript, de modo que se pueden incluir código JavaScript en las consultas (usando la claúsula $where), enviarlo directamente a la base de datos para ejecutarlo, y usarlo para llevar a cabo agregaciones.

Por seguridad, en MongoCode utilice el campo scope cuando vaya a usar variables PHP en JavaScript. Cuando el código no requiera de valores externos, se puede o bien usar MongoCode o símplemente un string. Revise la sección de seguridad para más información sobre cómo enviar código JavaScript a la base de datos.

Arrays y Objetos

También pueden guardarse arrays y objetos en la base de datos. Los arrays con clave numérica incremental se almacenarán como arrays. En cualquier otro caso, se almacenarán como objetos.

<?php

// $puntuaciones se almacenará como array
$puntuaciones = array(981007385);
$collection->insert(array("puntuaciones" => $puntuaciones));

// $puntuaciones se almacenará como un objeto
$puntuaciones = array("pregunta1" => 98"examen" => 100"pregunta2" => 73"final" => 85);
$collection->insert(array("puntuaciones" => $puntuaciones));

?>

Si consultamos estos objetos en la consola de la base de dato, obtendremos algo similar a esto:

> db.students.find()
{ "_id" : ObjectId("4b06beada9ad6390dab17c43"), "puntuaciones" : [ 98, 100, 73, 85 ] }
{ "_id" : ObjectId("4b06bebea9ad6390dab17c44"), "puntuaciones" : { "pregunta1" : 98, "examen" : 100, "pregunta2" : 73, "final" : 85 } }

La base de datos puede almacenar también objetos PHP arbitrarios (pese a que se devolverán como arrays asociativos). Los campos se usan para pares clave/valor. Por ejemplo, la entrada de un blog podría ser así:

<?php

  
// clase de la entrada de un blog
  
class Entrada {

  var 
$autor;
  var 
$contenido;
  var 
$comentarios = array();
  var 
$fecha;

  public function 
__construct($autor$contenido) {
  
$this->autor $autor;
$this->contenido $contenido;
    
$this->fecha = new MongoDate();
  }

  public function 
establecerTitulo($titulo) {
    
$this->titulo $titulo;
  }
}

// crear una entrada de blog sencilla e insertarla en base de datos
$entrada1 = new Entrada("Adam""Esto es una entrada de un blog");

$blog->insert($entrada1);


// no hay niguna restricción del tipo usado en el campo "autor", de manera que podemos
// usarlo como un objeto anidado
$autor = array("nombre" => "Fred""karma" => 42);
$entrada2 = new Entrada($autor"Ésta es otra entrada de blog.");

// creamos un campo más para el título
$entrada2->establecerTitulo("Segunda Entrada");

$blog->insert($entrada2);

?>

En la consola de la base de datos, lo veríamos parecido a esto:

> db.blog.find()
{ "_id" : ObjectId("4b06c263edb87a281e09dad8"), "autor" : "Adam", "contenido" : "Esto es una entrada de un blog", "comentarios" : [ ], "fecha" : "Fri Nov 20 2009 11:22:59 GMT-0500 (EST)" }
{ "_id" : ObjectId("4b06c282edb87a281e09dad9"), "autor" : { "nombre" : "Fred", "karma" : 42 }, "contenido" : "Ésta es otra entrada de blog", "comentarios" : [ ], "fecha" : "Fri Nov 20 2009 11:23:30 GMT-0500 (EST)", "titulo" : "Segunda Entrada" }

El driver no detecta referencias cíclicas en arrays ni en objetos. Por ejemplo, esto emitiría un error fatal:

<?php

$collection
->insert($GLOBALS);

?>
Fatal error: Nesting level too deep - recursive dependency?
Si se necesitara insertar documentos que pudieran tener dependencias cíclicas, deberá comprobarse a mano antes de pasarlo al driver.