5.5.15

Consultas

Distribuyendo consultas a esclavos

Todas las consultas (lecturas y escrituras) solamente se envian al miembro primario de un conjunto de réplicas de manera predeterminada. Sin embargo, esto es fácilmente configurable usando las Preferencias de lectura, que permiten establecer algunas preferencias de lectura genéricas (tales como permitir que un secundario lea del servidor más cercano), y también proporcionar formas de dirigir específicamente un servidor en un país concreto, o incluso hardware, usando los conjuntos de etiquetas de conjuntos de réplicas.

Las preferencias de lectura se pueden configurar a "cualquier nivel"

Cada clase hereda la configuración de preferencias de lectura de su clase superior, por lo que si se hace:

Ejemplo #1 Heredar ReadPreferences del nivel de la base de datos hacia el Cursor

<?php
$db
->setReadPreference(MongoClient::RP_SECONDARY_PREFERRED);
$c $db->myCollection;

$cursor $c->find();
?>

entonces, la consulta será ejecutada en un secundario (la colección MongoClient::RP_SECONDARY_PREFERRED heredada de la base de datos y el cursor heredado de la colección).

Cómo se escogen los esclavos

Cada instancia de MongoClient escoge su propio secundario utilizando el secundario disponible con el menor tiempo de respuesta. Es decir, si tuviéramos un cliente PHP en Europa y otro en Australia y tuviéramos un secundario en cada uno de estos centros de datos, podríamos hacer:

<?php
$options 
= array("replicaSet" => "setName""readPreference" => MongoClient::RP_SECONDARY_PREFERRED);

// en el cliente de Australia
$m = new MongoClient("mongodb://primary,australianhost.secondary,europeanhost.secondary"$options);
$cursor $m->foo->bar->find();
$cursor->getNext();
echo 
"Leyendo desde: "$cursor->info()["server"], "\n";

// en el cliente de Europa
$m = new MongoClient("mongodb://primary,australianhost.secondary,europeanhost.secondary"$options);
$cursor $m->foo->bar->find();
$cursor->getNext();
echo 
"Leyendo desde: "$cursor->info()["server"], "\n";
?>

El resultado del ejemplo sería algo similar a:

Reading from: australianHost
Reading from: europeanHost

Tenga en cuenta que se debe realizar una consulta antes de elegir un secundario: los secundarios los elige el controlador de forma retardada, y para cada consulta por separado.

Se puede ver los que el controlador piensa que es el estado actual de los miembros del conjunto ejecutando MongoClient::getHosts() o MongoClient::getConnections().

Si un secundario no es legible, el controlador enviará las lecturas al primario que se especificó con MongoClient::RP_SECONDARY_PREFERRED, que recurrirá a ejecutar una consulta en un primario si no estuviera disponible un secundario. Un servidor es considerado legible si su estado es 2 (SECONDARY) y su salud es 1. Se puede verificar esto con MongoClient::getHosts() y MongoClient::getConnections().

Notas aleatorias

Las escrituras siempre se envian al primario y, de forma predeterminada, todas las lecturas son enviada también al primario.

Consultando por _id

A cada objeto que se inserta se le asigna automáticamente un campo _id único, el cual, a menudo, es un campo útil para usarlo en consultas. Esto funciona de forma similar a la funcionalidad "obtener el último ID insertado", excepto que el _id es escogido por el cliente.

Supongamos que queremos localizar el documento que acabamos de insertar. Las inserciones añaden un campo _id al documento, de modo que podemos consultar en base a él:

<?php
$person 
= array("name" => "joe");

$people->insert($person);

// ahora $joe tiene un campo _id
$joe $people->findOne(array("_id" => $person['_id']));
?>

Salvo que se indique lo contrario, el campo _id será de tipo MongoId. El error más frecuente consiste en usar una cadena de texto que concuerde con un MongoId. Debe tenerse presente que son dos tipos de datos distintos, y no concuerdan, del mismo modo que el texto "array()" no es lo mismo que un array vacío. Por ejemplo:

<?php
$person 
= array("name" => "joe");

$people->insert($person);

// convertimos el _id a texto
$pid $person['_id'] . "";

// FALLO - $pid es un texto, no un MongoId
$joe $people->findOne(array("_id" => $pid));
?>

Arrays

Los arrays son especiales por varias razones. En primer lugar, hay dos tipos de arrays que MongoDB utiliza: arrays "normales" y arrays asociativos. Los arrays asociativos pueden tener cualquier combinación de claves y valores. Los arrays "normales" se definen como arrays con un índice numérico ascendente que comienza por 0 y se incrementa en uno por cada elemento. Estos son, normalmente, los arrays de PHP más comunes.

Por ejemplo, si se quisiera guardar una lista de premios en un documento, podríamos poner:

<?php

$collection
->save(array("awards" => array("gold""silver""bronze")));

?>

Las consultas pueden llegar hasta los arrays en busca de elementos. Supongamos que queremos encontrar todos los documentos que contienen un elemento de un array con un determinado valor. Por ejemplo, documentos con un premio "gold", como por ejemplo:

{ "_id" : ObjectId("4b06c282edb87a281e09dad9"), "awards" : ["gold", "silver", "bronze"]}

Esto puede lograrse con una única consulta, ignorando el hecho de que "awards" es un array:

<?php

  $cursor 
$collection->find(array("awards" => "gold"));

?>

Supongamos que estamos consultando un objeto más complejo, si cada elemento del array fuera un objeto en sí mismo, como en:

{
     "_id" : ObjectId("4b06c282edb87a281e09dad9"),
     "awards" :
     [
        {
            "first place" : "gold"
        },
        {
            "second place" : "silver"
        },
        {
            "third place" :  "bronze"
        }
     ]
}

Incluso aquí, ignorando que se trata de un array, podemos usar la misma notación para consultar al subobjeto:

<?php

$cursor 
$collection->find(array("awards.first place" => "gold"));

?>

Debe tenerse en cuenta que no importa que haya espacios en los nombres de campos (pese a que sea mejor no usarlos, sólo por mantenerlo más legible).

Puede también usarse un array para consultar un determinado número de posibles valores. Por ejemplo, si buscáramos documentos "gold" o "copper", podríamos hacer:

<?php

$cursor 
$collection->find(array("awards" => array('$in' => array("gold""copper"))));

?>

Historial de cambios

Versión Descripción
1.3.0 Se introdujo el framwork Preferencias de Lectura para poder tener más control sobre las lecturas de secundarios.
1.3.0 Uso obsoleto de slaveOkay, la alternativa es Preferencias de Lectura.
1.1.0 Se introdujo la posibilidad de enviar lecturas a secundarios de miembros de conjuntos de réplicas usando Mongo::setSlaveOkay()
add a note add a note

User Contributed Notes 3 notes

up
2
Charle Demers
4 years ago
Watch for types casting in your queries, make sure ints are typed as ints and strings as strings.

Ex:
<?php

$friendId
= $_SESSION['friendId'];
$request = array( 'friends.friendId' => (int)$friendId );
$friend = $this->_mongo->friends->findOne( $request );

?>

This example would not work without casting the $friendId to int in the request array (unless the friendId column in Mongo is actually really a string).
up
0
patrick at hexane dot org
2 years ago
Note that $db->collection->find()->count() will always run on the PRIMARY, since underneath the hood ->count() is a dbcommand.
up
0
jhuntwork at lightcubesolutions dot com
4 years ago
If you have already converted the MongoID into a string elsewhere and need to query for an _id based on the string, you can do so by creating a new MongoID object:

<?php

$m
= new Mongo();
$collection = $collection = $m->selectDB('foo')->selectCollection('bar');

$id_string = '4b7c29908ead0e2e1d000000';

// The string is converted to a MongoID object
$mongo_id = new MongoID($id_string);

// $obj will be an array of data if the _id exists in the collection
$obj = $collection->findOne(array('_id'=>$mongo_id));

?>
To Top