PHP Unconference Europe 2015

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.

Chaque classe hérite de la configuration des préférences de lecture de la classe sous-jacente, aussi, si vous faîtes :

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();
?>

alors, 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"))));

?>

Historique

Version Description
1.3.0 Introduction du framework pour les préférence de lecture permettant une contrôle fin des lectures sur les secondaires.
1.3.0 L'utilisation de slaveOkay devient obsolète ; l'alternative est les préférences de lecture.
1.1.0 Introduction de la possibilité de router les lectures vers les secondaires des membres du jeu de réplication, en utilisant la méthode 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