Запросы

Распределение запросов к вторичным серверам

Все запросы (чтение и запись) отправляются только основному члену реплики, установленному по умолчанию. Это, однако, легко настраивается с помощью предпочтений чтения, которые позволяют вам установить некоторые общие предпочтения чтения (например, разрешить чтение c ближайшего вторичного сервера), а также предоставляют способы для целевого назначения сервера в конкретной стране, центре обработки данных или даже оборудовании, путем использования наборов тегов реплики.

Настройки чтения могут быть настроены на каждом уровне драйвера:

Каждый класс наследует настройку предпочтений чтения из "родительского" контекста.

Пример #1 Наследование предпочтений чтения от уровня базы данных до курсора

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

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

В этом примере запрос будет выполнен к вторичному серверу. Коллекция наследует MongoClient::RP_SECONDARY_PREFERRED базы данных, а курсор наследует ее от коллекции.

Как выбираются вторичные сервера

Каждый экземпляр MongoClient выбирает свой собственный вторичный сервер, используя доступный вторичный сервер с наименьшим временем проверки связи. Итак, если бы у нас был сервер PHP в Европе и в Австралии, и у нас было по одному вторичному серверу в каждом из этих центров обработки данных, мы могли бы сделать:

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

// на австралийском сервере
$m = new MongoClient("mongodb://primary,australianhost.secondary,europeanhost.secondary"$options);
$cursor $m->foo->bar->find();
$cursor->getNext();
echo 
"Чтение с: "$cursor->info()["server"], "\n";

// на европейском сервере
$m = new MongoClient("mongodb://primary,australianhost.secondary,europeanhost.secondary"$options);
$cursor $m->foo->bar->find();
$cursor->getNext();
echo 
"Чтение с: "$cursor->info()["server"], "\n";
?>

Результатом выполнения данного примера будет что-то подобное:

Чтение с: australianHost
Чтение с: europeanHost

Обратите внимание, что мы должны выполнить запрос до того, как будет выбран вторичный сервер лениво драйвером и для каждого запроса отдельно.

Вы можете увидеть, что драйвер считает текущим состоянием членов набора, запустив MongoClient::getHosts() или MongoClient::getConnections().

Если ни один вторичный сервер не доступен для чтения, драйвер будет отправлять чтение основному, как мы указали MongoClient::RP_SECONDARY_PREFERRED, который будет выполнять откат для выполнения запроса на основном сервере, если вторичные серверы недоступны. Сервер считается читаемым, если его состояние равно 2 (SECONDARY), а его состояние равно 1. Вы можете проверить это с помощью MongoClient::getHosts() и MongoClient::getConnections().

Случайные заметки

Записи всегда отправляются основному серверу, и по умолчанию все операции чтения отправляются также основному серверу.

Запросы по _id

Каждому вставленному объекту автоматически присваивается уникальное поле _id, которое часто является полезным полем для запросов. Работает аналогично функциональности "получить последний идентификатор вставки", за исключением того, что _id выбирается клиентом.

Предположим, что мы хотим найти документ, который мы только что вставили. Вставка добавляет поле _id к документу, поэтому мы можем выполнить запрос следующим образом:

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

$people->insert($person);

// сейчас у $joe есть поле _id
$joe $people->findOne(array("_id" => $person['_id']));
?>

Если пользователь не указал иное, поле _id является MongoId. Самая распространенная ошибка - попытка использовать строку для совпадения с MongoId. Помните, что это два разных типа данных, и они не будут соответствовать друг другу так же, как строка "array()" не совпадает с пустым массивом. Например:

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

$people->insert($person);

// преобразовываем _id в строку
$pid $person['_id'] . "";

// ОШИБКА - $pid является строкой, а не MongoId
$joe $people->findOne(array("_id" => $pid));
?>

Массивы

Массивы особенные в нескольких отношениях. Во-первых, есть два типа, которые использует MongoDB: "нормальные" массивы и ассоциативные массивы. Ассоциативные массивы могут иметь любое сочетание ключевых типов и значений. "Нормальные" массивы определяются как массивы с возрастающими числовыми индексами, начинающимися с 0 и увеличивающимися на единицу для каждого элемента. Как обычный PHP-массив.

Например, если вы хотите сохранить список наград в документе, вы можете выполнить:

<?php

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

?>

Запросы могут попадать в массивы для поиска элементов. Предположим, что мы хотим найти все документы с элементом массива заданного значения. Например, документы с "gold" наградой, такие как:

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

Это можно сделать простым запросом, игнорируя тот факт, что "awards" - это массив:

<?php

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

?>

Предположим, что мы запрашиваем более сложный объект, если каждый элемент массива был самим объектом, например:

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

Не обращая внимания на то, что это массив, мы можем использовать точечную нотацию для запроса подобъекта:

<?php

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

?>

Обратите внимание, что не имеет значения, что в имени поля есть пробел (хотя может быть лучше не использовать пробелы, просто чтобы сделать вещи более читабельными).

Вы также можете использовать массив для запроса количества возможных значений. Например, если бы мы искали документы "gold" или "copper", мы могли бы сделать:

<?php

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

?>

Список изменений

Версия Описание
1.3.0 Введена структура предпочтений чтения, позволяющая более детально контролировать операции чтения со вторичных серверов.
1.3.0 Устарело использование slaveOkay, альтернатива - предпочтения чтения.
1.1.0 Введена возможность маршрутизации чтения на вторичных серварах членов набора реплик с использованием Mongo::setSlaveOkay()