Interrogation
Distribution des requêtes aux secondaires
Toutes les requêtes (en lecture et en écriture) ne sont envoyées qu'au membre
primaire du jeu de réplication par défaut. Ce comportement est cependant
facilement configurable en utilisant les
préférences de lecture qui
vous permettent de définir quelques préférences de lecture génériques (comme
l'autorisation des lectures sur un secondaire du serveur le plus proche),
mais aussi fournissent une façon de spécifier un serveur précis, dans un pays
spécifique, un centre de données précis, ou même un matériel donné, en utilisant
les tags des jeux de réplication.
Les préférences de lecture peuvent être configurées à tous les niveaux du driver.
Chaque classe hérite de la configuration des préférences de lecture de le contexte appelant.
Exemple #1 Héritage des préférences de lecture depuis le niveau de la base de données vers le curseur
<?php
$db->setReadPreference(MongoClient::RP_SECONDARY_PREFERRED);
$c = $db->myCollection;
$cursor = $c->find();
?>
Dans cet exemple, la requête sera exécutée sur un secondaire. La collection hérite de
MongoClient::RP_SECONDARY_PREFERRED
depuis la base de données,
et le curseur en hérite de la collection.
Comment les secondaires sont-ils choisis ?
Chaque instance de MongoClient choisit son secondaire
en utilisant le secondaire ayant le ping le moins élevé. Ainsi, si nous
avons un client PHP en Europe et un en Australie et que nous
avons un secondaire dans chacun de ces data-centers, nous pouvons faire :
<?php
$options = array("replicaSet" => "setName", "readPreference" => MongoClient::RP_SECONDARY_PREFERRED);
// sur un client Australien
$m = new MongoClient("mongodb://primary,australianhost.secondary,europeanhost.secondary", $options);
$cursor = $m->foo->bar->find();
$cursor->getNext();
echo "Lecture depuis : ", $cursor->info()["server"], "\n";
// sur un client européen
$m = new MongoClient("mongodb://primary,australianhost.secondary,europeanhost.secondary", $options);
$cursor = $m->foo->bar->find();
$cursor->getNext();
echo "Lecture depuis : ", $cursor->info()["server"], "\n";
?>
L'exemple ci-dessus va afficher quelque chose de similaire à :
Lecture depuis : australianHost
Lecture depuis : europeanHost
Notez que nous devons exécuter une requête avant qu'un secondaire
ne soit choisi : les secondaires sont choisis par le driver et pour
chaque requête, séparément.
Vous pouvez voir le choix du driver, en analysant le statut courant
du membres du jeu, en exécutant la méthode MongoClient::getHosts() ou
la méthode MongoClient::getConnections().
Si aucun secondaire n'est lisible, le driver enverra les lectures au primaire,
tel que nous l'avons spécifié avec
MongoClient::RP_SECONDARY_PREFERRED
, qui aura comme comportement
de repli que d'exécuter une requete sur un primaire, si aucune secondaire n'est
disponible. Un serveur est considéré comme lisible si son état vaut 2 (secondaire)
et sa santé vaut 1. Vous pouvez vérifier cela avec les méthodes
MongoClient::getHosts() et
MongoClient::getConnections().
Diverses notes
Les écritures sont toujours envoyées au serveur principal et par défaut,
toutes les lectures sont aussi envoyées au primaire.
Interrogation sur un _id
Chaque objet inséré se voit assigné automatiquement un champ unique _id
,
qui est bien utile pour être utilisé dans les requêtes. Ceci fonctionne de façon
similaire à la fonctionalité "donne moi le dernier ID inséré", excepté que
_id
est choisi par le client.
Supposez que vous voulez trouver un document que vous venez tout juste d'insérer.
L'insertion ajoute un champ _id
au document, aussi, vous pouvez
effectuer votre requête de la sorte :
<?php
$person = array("name" => "joe");
$people->insert($person);
// Maintenant, $joe a un champ _id
$joe = $people->findOne(array("_id" => $person['_id']));
?>
Tant que l'utilisateur ne l'a pas spécifié autrement, le champ _id
est un MongoId. L'erreur la plus courante
est d'essayer d'utiliser une chaîne qui correspond à un
MongoId. Gardez à l'esprit que cet identifiant
a 2 types de données différents, et ne correspond pas l'un l'autre,
de la même façon que la chaîne "array()" n'est pas la même chose
qu'un tableau vide. Par exemple :
<?php
$person = array("name" => "joe");
$people->insert($person);
// Conversion de l'_id en une chaîne
$pid = $person['_id'] . "";
// ECHEC - $pid est une chaîne, et non un MongoId
$joe = $people->findOne(array("_id" => $pid));
?>
Les tableaux
Les tableaux sont spéciaux à plus d'un titre. Tout d'abord, il y a 2 types
utilisés par MongoDB : des tableaux "normaux" et des tableaux associatifs.
Les tableaux associatifs peuvent avoir plusieurs types de clés et de valeurs.
Les tableaux "normaux" sont définis comme tableaux dans ces indices numériques
ascendants, en commençant par 0 et s'incrémentant de 1 pour chaque élément.
Ces 2 types correspondent à ce que vous connaissez déjà comme type en PHP.
Actuellement, si vous voulez sauvegarder la liste des récompenses
dans un document, vous pouvez :
<?php
$collection->save(array("awards" => array("gold", "silver", "bronze")));
?>
Les requêtes peuvent effectuer des recherches directement dans les éléments.
Supposez que nous souhaitons trouver tous les documents dont l'élément du
tableau est à une valeur fournie. Par exemple, les documents dont la
récompense est l'or, comme ceci :
{ "_id" : ObjectId("4b06c282edb87a281e09dad9"), "awards" : ["gold", "silver", "bronze"]}
Ceci peut être effectué avec une requête simple, en ignorant le fait que "awards"
est un tableau :
<?php
$cursor = $collection->find(array("awards" => "gold"));
?>
Supposez que vous interrogiez la base de données avec un objet plus complexe,
dont chaque élément du tableau sont eux-mêmes des objets, comme ceci :
{
"_id" : ObjectId("4b06c282edb87a281e09dad9"),
"awards" :
[
{
"first place" : "gold"
},
{
"second place" : "silver"
},
{
"third place" : "bronze"
}
]
}
Continuons d'ignorer que c'est un tableau. Nous pouvons utiliser
la notation basée sur les points pour interroger le sous-objet :
<?php
$cursor = $collection->find(array("awards.first place" => "gold"));
?>
Notez qu'il importe peu qu'il y ait un espace dans le nom du champ
(bien qu'il convient de ne pas en mettre, juste pour rendre le code
plus lisible).
Vous pouvez également utiliser un tableau contenant plusieurs valeurs
à chercher. Actuellement, si nous cherchons les documents "gold" et "copper",
nous pouvons le faire comme ceci :
<?php
$cursor = $collection->find(array("awards" => array('$in' => array("gold", "copper"))));
?>