PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 170 · После Manager, Query, команд и базовых обновлений
MongoDB: операции выбранного Server и понятный Stable API
Запросы страниц, пакеты изменений, индексы, сохранённые отчёты и границы Stable API — от короткого вызова до видимого результата.
От выбора узла к полезному результату
Каталог должен показать только нужные товары, импорт — сохранить изменения, а отчёт — вернуть полезные цифры. Иногда важно выполнить эти действия на уже выбранном узле и точно понимать, какие правила API действуют. Здесь Manager выбирает Server, Server выполняет запрос или команду, а человек видит реальные товары, остатки, индекс и сохранённый отчёт.
- URI учебной базы → Manager → selectServer(PRIMARY) → конкретный Server
- Query/Command/BulkWrite → метод Server → MongoDB выполняет действие
- Cursor/WriteResult → ограниченное чтение → таблица товара, отчёта или результата изменения
Можно представить Manager диспетчером, который выбирает подходящую рабочую точку, а Server — обращением к конкретной точке. Аналогия объясняет разделение обязанностей, но не означает отдельный физический компьютер для каждого объекта или вечную неизменность роли узла.
$preference = new MongoDB\Driver\ReadPreference('primary');
$server = $manager->selectServer($preference);
$query = new MongoDB\Driver\Query(['sku' => 'MUG'], ['limit' => 1]);
$cursor = $server->executeQuery($namespace, $query);Знак $ начинает имя переменной; = сохраняет возвращённый объект. new создаёт настройки ReadPreference или Query. Стрелка -> вызывает метод у объекта слева. selectServer возвращает Server, executeQuery — Cursor с результатом. $manager и $namespace готовит полная программа ниже; короткий фрагмент показывает только связь вызовов. В первом уроке найденный артикул MUG будет виден в таблице.
Начальные объяснения: переменные, массив с именованными ключами, аргументы и return, подключение и простые CRUD-операции. Подробная диагностика узлов уже есть в главе выбора Server; здесь продолжаем выполнением операций.
Выбрать метод по характеру операции
| Задача | Метод Server | Полезный результат |
|---|---|---|
| Выбрать документы | executeQuery | Cursor ограниченной страницы |
| Пакет одной коллекции | executeBulkWrite | WriteResult с итогами |
| Пакет нескольких namespace MongoDB8 | executeBulkWriteCommand | BulkWriteCommandResult |
| Команда только чтения | executeReadCommand | Cursor отчёта/описания |
| Команда чтения с записью | executeReadWriteCommand | Сохранённый отчёт, отдельно прочитанный Query |
| Команда структуры/записи | executeWriteCommand | Ответ createIndexes и проверяемое ограничение |
| Низкоуровневая диагностика | executeCommand | Ответ команды с явно понятными правилами |
| Стабильный набор возможностей | ServerApi в Manager | Рабочие API-команды и отказ вне договора |
Подготовка и запуск девяти программ
Каждый из девяти архивов самостоятельный: example.php, sr129-helper.php и README. Нужны PHP CLI8.4+ x64, ext-mongodb2.5+ и отдельный MongoDB Community8.0+. Среда проверки пакета — PHP8.5.11 / mongodb2.5.5 / MongoDB8.0.34; Composer не нужен.
$env:PHPMAN_MONGODB_URI='mongodb://127.0.0.1:27075/?directConnection=true&retryWrites=false'
$env:PHPMAN_MONGODB_DATABASE='php_manual_lab'
php example.phpКоманды PowerShell запускаются из распакованного каталога. README объясняет установку и запуск отдельного mongod. Программа создаёт собственные случайные коллекции: одну, либо две для разных namespace/сохранения отчёта. finally удаляет только их точные имена, затем проверяется отсутствие. Пользовательские коллекции и настройки сервера не меняются.
result.html — понятная таблица; result.json — те же столбцы и значения; metrics.json — версии, проверки и SHA256 файлов. Host/port записываются из фактического Server и сравниваются с URI; они не выдуманы ради ожидаемой таблицы. Ссылки на странице открывают сохранённые результаты запуска, не подключая браузер читателя к MongoDB.
Получить Server от Manager и проверить, кто вернул документ
Отчёт вернул товар, но при диагностике нужно понимать, какой узел ответил. Научимся получить объект Server от Manager и связать реальную выборку с её сервером.
Исходные данные
В собственной коллекции один товар MUG. URI указывает отдельный локальный mongod. Порт читается из URI и сверяется с наблюдаемым ответом, а не подменяется константой в отчёте.
- Manager: selectServer получает ReadPreference::PRIMARY и возвращает Server
- Server: executeQuery отправляет ограниченный поиск _id=1 этому узлу
- Cursor: getServer сообщает узел выполненной операции; таблица показывает товар и совпадение адреса
Самый короткий полезный вызов
$server = $manager->selectServer(
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)
);
$cursor = $server->executeQuery($namespace, $query);
// Manager выбирает; Server выполняет; Cursor содержит результат.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Проверка | Результат |
|---|---|
| Полученный товар | MUG |
| Ответил выбранный Server | true |
| Порт совпадает с URI | true |
| new Server недоступен | true |
Пошаговый разбор
Manager управляет топологией и выбирает подходящий узел. Server представляет конкретный известный этому Manager сервер. Это разные обязанности: Server не является вторым объектом конфигурации подключения.
Конструктор Server private. new Server() нельзя использовать вместо Manager. Рабочие способы получения — Manager::selectServer(), Manager::getServers() и Server уже выполненного Cursor. Список известных узлов сам по себе не означает, что любой из них годится для записи.
Вызов -> выполняет метод объекта слева. selectServer возвращает значение, которое сохраняется в $server. Затем executeQuery возвращает Cursor; его данные читаются, а getServer позволяет сравнить endpoint с выбранным объектом.
PRIMARY в современной ReadPreference — строковый режим. Исторические RP_PRIMARY и целочисленный режим из старых примеров не переносятся механически в mongodb2.x. Проверяйте совместимость расширения и Composer-библиотеки, если используете её.
Границы и ошибки
Здесь standalone: в нём нет secondary или выбора между репликами. Успешный запуск доказывает адрес и результат этого запроса, а не задержку репликации, failover или высокую доступность. Server не закрепляет за приложением роль primary навечно: топология может измениться.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'sku'=>'MUG','title'=>'Кружка']]);
$cursor=$server->executeQuery($namespace,new MongoDB\Driver\Query(['_id'=>1],['projection'=>['_id'=>1,'sku'=>1],'limit'=>1,'batchSize'=>2,'maxTimeMS'=>1500]));
$docs=sr129Rows($cursor);$actual=$cursor->getServer();$parts=parse_url($settings['uri']);
$private=false;try{new MongoDB\Driver\Server();}catch(Error){$private=true;}
$same=$actual->getHost()===$server->getHost()&&$actual->getPort()===$server->getPort();
$rows=[['Полученный товар',$docs[0]['sku']],['Ответил выбранный Server',$same],['Порт совпадает с URI',$actual->getPort()===$parts['port']],['new Server недоступен',$private]];
$checks=['exact_doc'=>$docs===[['_id'=>1,'sku'=>'MUG']],'same_server'=>$same,'port_checked_against_uri'=>$actual->getPort()===$parts['port'],'host_is_loopback'=>$actual->getHost()==='127.0.0.1','private_constructor'=>$private,'standalone_not_replica'=>$server->getType()===MongoDB\Driver\Server::TYPE_STANDALONE];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-selected-server', ['Проверка', 'Результат'], $rows, $checks, $runtime);
echo 'mongodb129-server-selected-server: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-selected-server: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Поменяйте SKU на BOOK — отчёт должен вернуть BOOK при том же наблюдаемом endpoint. В реальном сервисе сохраняйте адрес для диагностики, но не показывайте внутреннюю топологию всем посетителям.
Реальная задача разработчика: Как понять, какой сервер ответил на запрос. Разработчику нужен адрес реально ответившего узла, а не просто список подключений. Вопрос о старом драйвере служит мотивацией; современный пример использует Cursor::getServer и не заявляет измерение репликации на standalone. Обсуждение даёт контекст; современный контракт сверяется с официальными источниками, а код и объяснения здесь самостоятельные.
Реальная задача разработчика: Почему старый целочисленный режим ReadPreference стал deprecated. Обновление окружения проявило несовместимость старого режима в библиотеке. Пример использует современную строку/константу; удалять строки vendor наугад не предлагается. Обсуждение даёт контекст; современный контракт сверяется с официальными источниками, а код и объяснения здесь самостоятельные.
Получить только видимые товары и нужные поля страницы
Экран каталога магазина A должен показать две доступные позиции, затем следующую страницу. Скрытые данные, чужие товары и черновики не должны покидать базу в этой выборке.
Исходные данные
Пять товаров: три активных магазина A по ценам100/200/300, один чужой и один черновик. Текст internal намеренно добавлен, чтобы проверить projection.
- Условие: tenant=A и active=true выполняются в MongoDB
- Страница: sort price,_id + limit2 + projection возвращают Кружку и Тарелку
- Продолжение: после пары price=200,_id=3 следующая выборка возвращает Чайник
Самый короткий полезный вызов
$query = new MongoDB\Driver\Query(
['tenant' => 'A', 'active' => true],
['projection' => ['_id' => 1, 'title' => 1, 'price' => 1],
'sort' => ['price' => 1, '_id' => 1], 'limit' => 2]
);
$cursor = $server->executeQuery($namespace, $query);Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Страница | ID | Название | Цена, условные единицы |
|---|---|---|---|
| 1 | 2 | Кружка | 100 |
| 1 | 3 | Тарелка | 200 |
| 2 | 1 | Чайник | 300 |
Пошаговый разбор
Query хранит условие и параметры чтения. Server::executeQuery выполняет его на выбранном узле. namespace включает имя базы и коллекции; это не имя одного поля.
projection перечисляет нужные поля: _id,title,price. sort задаёт порядок, limit ограничивает число документов. Сервер фильтрует и сортирует данные до передачи; не нужно загружать весь каталог и затем сортировать PHP-массив.
Для следующей страницы используется последняя пара price/_id: либо цена больше, либо цена та же и ID больше. _id снимает неоднозначность равных цен. Это пример продолжения по ключу, а не загрузка и пропуск всех предыдущих строк.
Третий аргумент executeQuery — массив options или null. В текущем2.x отдельный объект ReadPreference на его месте недопустим. Если указать readPreference внутри массива, другой Server автоматически выбран не будет.
Границы и ошибки
Поле tenant в коде задано приложением; пользовательский ввод нельзя без проверки превращать в условие чужого магазина. Составной индекс под фильтр/сортировку и explain нужны для реального объёма. Изменение цен между страницами может менять порядок: это не согласованный снимок каталога.
Индексы и план чтения · Ограничение памяти при чтении.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'tenant'=>'A','active'=>true,'title'=>'Чайник','price'=>300,'internal'=>'hidden'],['_id'=>2,'tenant'=>'A','active'=>true,'title'=>'Кружка','price'=>100,'internal'=>'hidden'],['_id'=>3,'tenant'=>'A','active'=>true,'title'=>'Тарелка','price'=>200,'internal'=>'hidden'],['_id'=>4,'tenant'=>'B','active'=>true,'title'=>'Чужой товар','price'=>10],['_id'=>5,'tenant'=>'A','active'=>false,'title'=>'Черновик','price'=>50]]);
$filter=['tenant'=>'A','active'=>true];$projection=['_id'=>1,'title'=>1,'price'=>1];
$first=sr129Query($server,$namespace,$filter,$projection,2,['price'=>1,'_id'=>1]);
$last=$first[count($first)-1];
$nextFilter=$filter+['$or'=>[['price'=>['$gt'=>$last['price']]],['price'=>$last['price'],'_id'=>['$gt'=>$last['_id']]]]];
$second=sr129Query($server,$namespace,$nextFilter,$projection,2,['price'=>1,'_id'=>1]);
$rows=[];foreach([1=>$first,2=>$second] as $page=>$docs){foreach($docs as $doc){$rows[]=[$page,$doc['_id'],$doc['title'],$doc['price']];}}
$checks=['page_one_ids'=>array_column($first,'_id')===[2,3],'page_two_id'=>array_column($second,'_id')===[1],'only_requested_fields'=>array_keys($first[0])===['_id','title','price'],'no_unrelated_or_draft'=>array_column(array_merge($first,$second),'_id')===[2,3,1],'page_bound'=>count($first)<=2&&count($second)<=2];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-query-page', ['Страница', 'ID', 'Название', 'Цена, условные единицы'], $rows, $checks, $runtime);
echo 'mongodb129-server-query-page: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-query-page: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Сделайте две одинаковые цены. Пара price/_id сохранит определённый порядок. Проверьте, что соседняя страница продолжает с большей пары; скрытое internal по-прежнему не возвращается.
Реальная задача разработчика: Почему третий аргумент executeQuery оказался несовместимым. В старом окружении библиотека и расширение ожидали разные формы третьего аргумента. Для2.5.5 показывается nullablearray options и точная история изменения API. Обсуждение даёт контекст; современный контракт сверяется с официальными источниками, а код и объяснения здесь самостоятельные.
Применить пакет изменений каталога и увидеть итог
При обновлении каталога нужно уменьшить остаток MUG, добавить PLATE и убрать DRAFT, затем убедиться, какие действия реально выполнены.
Исходные данные
До пакета: MUG qty5 и DRAFT qty0. Три операции относятся к одному namespace. Ожидается MUG qty3 и PLATE qty7.
- Подготовка: BulkWrite накапливает update,insert,delete без немедленной отправки
- Отправка: Server::executeBulkWrite применяет пакет с подтверждением w=1
- Контроль: WriteResult даёт1insert/1update/1delete; Query показывает реальные остатки
Самый короткий полезный вызов
$bulk = new MongoDB\Driver\BulkWrite();
$bulk->update(['_id' => 1, 'qty' => ['$gte' => 2]],
['$inc' => ['qty' => -2]], ['multi' => false, 'upsert' => false]);
$result = $server->executeBulkWrite($namespace, $bulk,
['writeConcern' => new MongoDB\Driver\WriteConcern(1, 3000)]);
// Подтверждённое изменение MUG: 5 → 3.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Артикул после пакета | Остаток |
|---|---|
| MUG | 3 |
| PLATE | 7 |
Пошаговый разбор
BulkWrite — список действий. Само добавление update ещё не меняет базу; вызов executeBulkWrite отправляет пакет. Драйвер старается объединять действия одного вида, но пакет не обязательно равен одному сетевому сообщению.
Уменьшение остатка защищено условием qty >= 2 и точным _id. $inc меняет значение сервером; multi=false и upsert=false ограничивают смысл. Если товар уже не подходит, MatchedCount будет0 — приложение должно обработать это как отсутствие выполненного резерва.
WriteResult отделяет совпавшие документы от изменённых. Это важнее самого факта «ошибки не было». Пустой BulkWrite специально отклоняется InvalidArgumentException; отправлять нечего.
ordered=true задаёт порядок и остановку после ошибки. Успешные предыдущие действия при этом не откатываются. Для общей атомарности нескольких документов нужен другой механизм, рассмотренный в главе транзакций.
Границы и ошибки
Этот набор неизменяем извне. w=1 означает подтверждение сервером, а не доказанную репликацию/журналирование. Объект BulkWrite одноразовый: для новой попытки создают новый пакет, а решение о повторе учитывает, что уже могло выполниться.
Условные атомарные изменения одного документа · Когда нужна транзакция нескольких действий · Частичный успех, WriteResult и ошибки подтверждения.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'sku'=>'MUG','qty'=>5],['_id'=>2,'sku'=>'DRAFT','qty'=>0]]);
$bulk=new MongoDB\Driver\BulkWrite(['ordered'=>true]);
$bulk->update(['_id'=>1,'qty'=>['$gte'=>2]],['$inc'=>['qty'=>-2]],['multi'=>false,'upsert'=>false]);
$bulk->insert(['_id'=>3,'sku'=>'PLATE','qty'=>7]);$bulk->delete(['_id'=>2],['limit'=>1]);
$result=$server->executeBulkWrite($namespace,$bulk,['writeConcern'=>new MongoDB\Driver\WriteConcern(1,3000)]);
$docs=sr129Query($server,$namespace,[],['_id'=>1,'sku'=>1,'qty'=>1],3);
$rows=[];foreach($docs as $doc){$rows[]=[$doc['sku'],$doc['qty']];}
$empty=false;try{$server->executeBulkWrite($namespace,new MongoDB\Driver\BulkWrite);}catch(MongoDB\Driver\Exception\InvalidArgumentException){$empty=true;}
$checks=['one_insert'=>$result->getInsertedCount()===1,'one_update'=>$result->getMatchedCount()===1&&$result->getModifiedCount()===1,'one_delete'=>$result->getDeletedCount()===1,'stock_result'=>array_column($docs,'qty')===[3,7],'deleted_draft'=>array_column($docs,'_id')===[1,3],'empty_batch_rejected'=>$empty];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-bulk-stock', ['Артикул после пакета', 'Остаток'], $rows, $checks, $runtime);
echo 'mongodb129-server-bulk-stock: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-bulk-stock: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Поставьте MUG qty1. Условие уменьшения не совпадёт, поэтому нынешняя проверка одного update остановит программу. Измените сценарий интерфейса так, чтобы показать «недостаточно остатка», а не объявлять резерв успешным.
Записать товар и запись журнала одним BulkWriteCommand
Импорт создаёт товар и запись журнала в разных коллекциях. Покажем API MongoDB8, где namespace указывается для каждой операции внутри одного BulkWriteCommand.
Исходные данные
Две новые собственные коллекции: каталог и журнал. В каталоге MUG qty4; в журнале событие catalog-import для MUG. Их случайные имена не выходят за список принадлежащих программе.
- Две операции: insertOne получает namespace каталога, затем namespace журнала
- Server: executeBulkWriteCommand отправляет команду bulkWrite MongoDB8
- Результат: insertedCount=2 и отдельное чтение подтверждают обе записи
Самый короткий полезный вызов
$bulk = new MongoDB\Driver\BulkWriteCommand();
$bulk->insertOne($catalogNamespace, ['_id' => 1, 'sku' => 'MUG', 'qty' => 4]);
$bulk->insertOne($journalNamespace, ['_id' => 1, 'event' => 'catalog-import']);
$result = $server->executeBulkWriteCommand($bulk);
// Два namespace внутри одной команды; это ещё не общая транзакция.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Назначение коллекции | Артикул | Сохранено |
|---|---|---|
| Каталог | MUG | qty=4 |
| Журнал | MUG | catalog-import |
Пошаговый разбор
BulkWriteCommand отличается от BulkWrite: namespace передаётся каждой операции. executeBulkWriteCommand поэтому не принимает отдельный namespace первым аргументом. Не смешивайте эти две сигнатуры.
Требуются ext-mongodb2.1+ и сервер MongoDB8.0+. Названия похожи, но новый метод использует серверную команду bulkWrite. В примере не нужен Composer.
BulkWriteCommandResult содержит итоги пакета. Счётчик вставок подтверждает две вставки; затем читаются оба документа с projection и limit1. Так проверяется полезный результат, а не только число операций.
Отдельная запись журнала в том же пакете удобна для импорта, но не гарантирует «товар и журнал существуют вместе». Если одно действие отказало после другого, возможен частичный результат. Критический бизнес-инвариант требует транзакции или специально спроектированного протокола.
Границы и ошибки
На MongoDB7 и старее этот API не заменяет старый BulkWrite. Пустой или уже отправленный BulkWriteCommand недопустим. Подробный разбор частичных ошибок приведён в связанной главе результатов записи; нельзя без анализа повторять весь пакет.
Условные атомарные изменения одного документа · Когда нужна транзакция нескольких действий · Частичный успех, WriteResult и ошибки подтверждения.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
$journalNs=sr129Create($manager,$database,$owned);
$bulk=new MongoDB\Driver\BulkWriteCommand;
$bulk->insertOne($namespace,['_id'=>1,'sku'=>'MUG','qty'=>4]);
$bulk->insertOne($journalNs,['_id'=>1,'event'=>'catalog-import','sku'=>'MUG']);
$result=$server->executeBulkWriteCommand($bulk,['writeConcern'=>new MongoDB\Driver\WriteConcern(1,3000)]);
$product=sr129Query($server,$namespace,['_id'=>1],['_id'=>0,'sku'=>1,'qty'=>1],1)[0];
$entry=sr129Query($server,$journalNs,['_id'=>1],['_id'=>0,'event'=>1,'sku'=>1],1)[0];
$rows=[['Каталог',$product['sku'],'qty='.$product['qty']],['Журнал',$entry['sku'],$entry['event']]];
$checks=['inserted_two'=>$result->getInsertedCount()===2,'two_own_namespaces'=>$namespace!==$journalNs&&count($owned)===2,'catalog_document'=>$product===['sku'=>'MUG','qty'=>4],'journal_document'=>$entry===['event'=>'catalog-import','sku'=>'MUG']];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===2;
sr129Report('mongodb129-server-bulk-command', ['Назначение коллекции', 'Артикул', 'Сохранено'], $rows, $checks, $runtime);
echo 'mongodb129-server-bulk-command: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-bulk-command: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Измените артикул одновременно в обеих операциях. Результат должен показать одинаковую связь товара и журнала. Затем сформулируйте, допустимо ли для вашего импорта отсутствие одной из двух записей.
Проверить узел и собрать маленький отчёт командой чтения
Панель магазина должна показать сумму только оплаченных заказов. Одновременно диагностика должна различать «узел отвечает» и «нужные данные действительно прочитаны».
Исходные данные
Четыре заказа: два оплаченных A на100 и250, черновик A на900 и оплаченный B на800. Пустой диагностический ping не заменяет запрос этих данных.
- ping: executeCommand возвращает подтверждение ответа узла
- aggregate: executeReadCommand: match A/paid,group →2заказа/350
- HTML: видны разные результаты диагностики и предметного отчёта
Самый короткий полезный вызов
$cursor = $server->executeReadCommand($database, $aggregateCommand,
['readConcern' => new MongoDB\Driver\ReadConcern('local')]);
// match shop=A,status=paid → group → 2 заказа и сумма350.
// executeCommand(ping) отдельно проверяет ответ узла, не доступ к заказам.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Показатель | Результат |
|---|---|
| Узел доступен | true |
| Оплаченных заказов магазина A | 2 |
| Сумма магазина A | 350 |
Пошаговый разбор
Command содержит документ команды; имя первой операции aggregate относится к MongoDB, а не к PHP-функции. $match отбирает нужные записи до группировки, $group считает на сервере, $limit ограничивает выход.
executeReadCommand применяет правила команды чтения: readPreference и readConcern берутся из операции/активной транзакции/URI по контракту. В примере local указан явно. Это уровень чтения, а не правило выбора другого объекта Server.
executeCommand является общим низкоуровневым методом. Вне активной транзакции он не наследует concern-настройки из URI так, как специализированные методы. Поэтому для отчёта применён read-метод, а generic оставлен для ping.
Cursor команды чтения даёт документы результата. Преобразование в массив здесь ограничено одной итоговой строкой; это не разрешение материализовать произвольную большую выборку.
Границы и ошибки
Ping может пройти при отсутствии прав на рабочую коллекцию. Проверка связи не гарантирует успех следующего запроса. Суммы здесь целые условные единицы; финансовая модель с валютой/Decimal128 требует отдельного контракта. local не обещает большинства реплик или транзакционного снимка.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'shop'=>'A','status'=>'paid','amount'=>100],['_id'=>2,'shop'=>'A','status'=>'paid','amount'=>250],['_id'=>3,'shop'=>'A','status'=>'draft','amount'=>900],['_id'=>4,'shop'=>'B','status'=>'paid','amount'=>800]]);
$ping=sr129Rows($server->executeCommand($database,new MongoDB\Driver\Command(['ping'=>1])))[0];
$command=new MongoDB\Driver\Command(['aggregate'=>$collection,'pipeline'=>[['$match'=>['shop'=>'A','status'=>'paid']],['$group'=>['_id'=>'$shop','orders'=>['$sum'=>1],'total'=>['$sum'=>'$amount']]],['$limit'=>1]],'cursor'=>['batchSize'=>2],'maxTimeMS'=>1500]);
$report=sr129Rows($server->executeReadCommand($database,$command,['readConcern'=>new MongoDB\Driver\ReadConcern('local')]))[0];
$rows=[['Узел доступен',(bool)$ping['ok']],['Оплаченных заказов магазина A',$report['orders']],['Сумма магазина A',$report['total']]];
$checks=['ping_ok'=>(bool)$ping['ok']===true,'selected_only_shop_a'=>$report['_id']==='A','paid_count'=>$report['orders']===2,'paid_total'=>$report['total']===350,'source_intact'=>count(sr129Query($server,$namespace,[],['_id'=>1],5))===4];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-read-command', ['Показатель', 'Результат'], $rows, $checks, $runtime);
echo 'mongodb129-server-read-command: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-read-command: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Смените статус черновика на paid: результат A станет3заказа и1250. Заказ магазина B должен остаться за пределами суммы.
Создать индекс собственной коллекции и проверить его правило
Нужно запретить два товара с одинаковым артикулом и безопасно повторять подготовку коллекции при запуске импорта.
Исходные данные
Два разных SKU в собственной коллекции. Создаётся уникальный индекс sku_unique, затем та же подготовка повторяется; попытка второго MUG должна отказать.
- Подготовка: executeWriteCommand выполняет createIndexes с unique=true
- Проверка: executeReadCommand listIndexes показывает фактическое правило
- Поведение: повтор подготовки успешен, повторный SKU отклонён, товаров по-прежнему2
Самый короткий полезный вызов
$command = new MongoDB\Driver\Command([
'createIndexes' => $collection,
'indexes' => [['key' => ['sku' => 1], 'name' => 'sku_unique', 'unique' => true]]
]);
$cursor = $server->executeWriteCommand($database, $command);
// Индекс не допускает второй документ с тем же sku.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Действие | Результат |
|---|---|
| Индекс | sku_unique |
| Правило unique | true |
| Повтор подготовки успешен | true |
| Повторный MUG отклонён | true |
| Товаров осталось | 2 |
Пошаговый разбор
executeWriteCommand нужен для команд записи вроде создания индекса или коллекции. Документация не рекомендует использовать его для сырых insert/update/delete: эти операции выполняются BulkWrite.
createIndexes получает имя коллекции и список индексов. key sku:1 задаёт поле; name — стабильное имя; unique=true создаёт ограничение. Стандартный индекс _id остаётся.
Повтор точно такого определения безопасен в нашей неизменяемой схеме. Другие параметры под тем же именем могут вызвать конфликт — не скрывайте его как успешную подготовку.
Попытка вставки MUG с новым _id отклоняется кодом11000, поскольку конфликтует sku. Пример ловит только этот ожидаемый отказ; ошибка связи или другое нарушение не превращается в «индекс работает».
Границы и ошибки
Индекс создаётся только в собственной маленькой коллекции. На рабочем объёме создание индекса требует планирования нагрузки и разбора существующих дублей. unique не означает автоматическое ускорение любого запроса; выбор индекса проверяют explain.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'sku'=>'MUG','qty'=>4],['_id'=>2,'sku'=>'PLATE','qty'=>7]]);
$command=new MongoDB\Driver\Command(['createIndexes'=>$collection,'indexes'=>[['key'=>['sku'=>1],'name'=>'sku_unique','unique'=>true]],'maxTimeMS'=>1500]);
$first=sr129Rows($server->executeWriteCommand($database,$command,['writeConcern'=>new MongoDB\Driver\WriteConcern(1,3000)]))[0];
$second=sr129Rows($server->executeWriteCommand($database,$command,['writeConcern'=>new MongoDB\Driver\WriteConcern(1,3000)]))[0];
$indexes=sr129Rows($server->executeReadCommand($database,new MongoDB\Driver\Command(['listIndexes'=>$collection,'cursor'=>['batchSize'=>10],'maxTimeMS'=>1500])));
$found=null;foreach($indexes as $index){if($index['name']==='sku_unique'){$found=$index;}}
$duplicate=false;$bulk=new MongoDB\Driver\BulkWrite;$bulk->insert(['_id'=>3,'sku'=>'MUG','qty'=>1]);
try{$server->executeBulkWrite($namespace,$bulk);}catch(MongoDB\Driver\Exception\BulkWriteException $error){$duplicate=$error->getCode()===11000;if(!$duplicate){throw $error;}}
$docs=sr129Query($server,$namespace,[],['_id'=>1,'sku'=>1],3);
$rows=[['Индекс',$found['name']],['Правило unique',$found['unique']],['Повтор подготовки успешен',(bool)$second['ok']],['Повторный MUG отклонён',$duplicate],['Товаров осталось',count($docs)]];
$checks=['write_command_ok'=>(bool)$first['ok']===true,'unique_index'=>$found!==null&&$found['key']===['sku'=>1]&&$found['unique']===true,'repeat_is_safe'=>(bool)$second['ok']===true,'duplicate_rejected'=>$duplicate,'catalog_intact'=>array_column($docs,'_id')===[1,2]];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-write-command', ['Действие', 'Результат'], $rows, $checks, $runtime);
echo 'mongodb129-server-write-command: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-write-command: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Переименуйте повторный SKU в BOOK: вставка станет допустимой, а проверку ожидаемого дубля нужно изменить. Так различаются конфликт _id и конфликт прикладного поля sku.
Сохранить и обновить готовый отчёт через aggregate и merge
Для панели нужен готовый небольшой отчёт по магазину, который можно сохранить и позже обновить из заказов, не пересчитывая весь набор в PHP.
Исходные данные
Три заказа: A100,A250,B800. Отчёт хранится во второй собственной коллекции под _id=A. Затем одна сумма A меняется с250 на300.
- Чтение: match shop=A →group даёт orders2,total350
- Запись: финальный $merge вставляет или заменяет отчёт A
- Обновление: после изменения исходника повторный merge даёт400 и сохраняет одну запись
Самый короткий полезный вызов
$cursor = $server->executeReadWriteCommand($database, $mergeCommand,
['writeConcern' => new MongoDB\Driver\WriteConcern(1, 3000)]);
// aggregate читает заказы, $merge пишет отчёт в отдельную свою коллекцию.
// Итог читается отдельным Query: A,2заказа,сумма350.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Этап | Магазин | Заказов | Сумма |
|---|---|---|---|
| Первое сохранение | A | 2 | 350 |
| После изменения исходной суммы | A | 2 | 400 |
Пошаговый разбор
Этот aggregate одновременно читает и пишет: стадия $merge обязана быть последней и указывает отдельную коллекцию результата. Поэтому используется executeReadWriteCommand.
on:_id задаёт ключ соответствия, whenMatched:replace заменяет существующий отчёт, whenNotMatched:insert создаёт новый. Мы заранее создаём выходную коллекцию и регистрируем её как собственную, чтобы очистка не затронула чужое.
Cursor такой команды не содержит строк отчёта: команда записала их в коллекцию. Отдельный ограниченный Query читает сохранённый результат. Пустой Cursor здесь не означает «отчёт не создан».
После изменения заказа повторная команда заменяет A, а не добавляет дубликат. Это полезно для пересчёта выбранной группы. Но $merge не удаляет ранее сохранённые группы, отсутствующие в новом результате: это не полная синхронизация всех данных.
Границы и ошибки
Чтение исходника и запись отчёта не превращаются в общую транзакцию. Здесь данные меняются последовательно в собственной лаборатории. В реальном сервисе нужны правила свежести, конкурентного пересчёта и удаления устаревших групп. Standalone-пример не проверяет маршрутизацию merge в replica set.
Условные атомарные изменения одного документа · Когда нужна транзакция нескольких действий · Частичный успех, WriteResult и ошибки подтверждения.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
$reportNs=sr129Create($manager,$database,$owned);$reportName=$owned[1];
sr129Insert($manager,$namespace,[['_id'=>1,'shop'=>'A','amount'=>100],['_id'=>2,'shop'=>'A','amount'=>250],['_id'=>3,'shop'=>'B','amount'=>800]]);
$command=new MongoDB\Driver\Command(['aggregate'=>$collection,'pipeline'=>[['$match'=>['shop'=>'A']],['$group'=>['_id'=>'$shop','total'=>['$sum'=>'$amount'],'orders'=>['$sum'=>1]]],['$limit'=>1],['$merge'=>['into'=>$reportName,'on'=>'_id','whenMatched'=>'replace','whenNotMatched'=>'insert']]],'cursor'=>['batchSize'=>2],'maxTimeMS'=>1500]);
$firstCursor=sr129Rows($server->executeReadWriteCommand($database,$command,['writeConcern'=>new MongoDB\Driver\WriteConcern(1,3000)]));
$before=sr129Query($server,$reportNs,['_id'=>'A'],['_id'=>1,'total'=>1,'orders'=>1],1)[0];
$bulk=new MongoDB\Driver\BulkWrite;$bulk->update(['_id'=>2],['$set'=>['amount'=>300]],['multi'=>false,'upsert'=>false]);$server->executeBulkWrite($namespace,$bulk);
$nextCursor=sr129Rows($server->executeReadWriteCommand($database,$command,['writeConcern'=>new MongoDB\Driver\WriteConcern(1,3000)]));
$after=sr129Query($server,$reportNs,[],['_id'=>1,'total'=>1,'orders'=>1],2);
$rows=[['Первое сохранение',$before['_id'],$before['orders'],$before['total']],['После изменения исходной суммы',$after[0]['_id'],$after[0]['orders'],$after[0]['total']]];
$checks=['merge_no_document_cursor'=>$firstCursor===[]&&$nextCursor===[],'initial_report'=>$before['total']===350&&$before['orders']===2,'refreshed_report'=>$after[0]['total']===400&&$after[0]['orders']===2,'one_report_not_duplicate'=>count($after)===1&&$after[0]['_id']==='A','only_own_targets'=>count($owned)===2&&$namespace!==$reportNs];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===2;
sr129Report('mongodb129-server-readwrite-command', ['Этап', 'Магазин', 'Заказов', 'Сумма'], $rows, $checks, $runtime);
echo 'mongodb129-server-readwrite-command: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-readwrite-command: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Удалите все заказы A перед пересчётом. Старая строка отчёта сама не исчезнет: отдельно определите политику для отсутствующих групп, вместо ожидания полного зеркалирования от $merge.
Различить незаданные и явные настройки Stable API
Перед обновлением сервера хочется ограничить приложение стабильным набором возможностей и увидеть, какие настройки на самом деле переданы драйверу.
Исходные данные
Три ServerApi: только V1; V1,false,false; V1,true,true. В собственной коллекции лежит MUG, который читается строгим API-клиентом.
- Настройка: ServerApi сохраняет версию1 и nullable-флаги
- Manager: объект передан в третьем аргументе driverOptions.serverApi
- Проверка: bsonSerialize показывает заданные поля; strict-клиент действительно читает MUG
Самый короткий полезный вызов
$api = new MongoDB\Driver\ServerApi(
MongoDB\Driver\ServerApi::V1, true, true
);
$manager = new MongoDB\Driver\Manager($uri, [], ['serverApi' => $api]);
echo json_encode($api->bsonSerialize(), JSON_THROW_ON_ERROR);
// {"version":"1","strict":true,"deprecationErrors":true}Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Настройка / операция | Наблюдаемое представление |
|---|---|
| По умолчанию | {"version":"1"} |
| Явное false | {"version":"1","strict":false,"deprecationErrors":false} |
| Строгий API | {"version":"1","strict":true,"deprecationErrors":true} |
| Чтение строгим клиентом | MUG |
Пошаговый разбор
Stable API — версия договора команд MongoDB. Число1 не означает MongoDB1, PHP1 или версию расширения. Константа называется V1 и содержит строку "1".
strict=true запрещает команды/возможности вне заявленного API. deprecationErrors=true просит сервер отклонять возможности, устаревшие в данном API. Это не управление PHP E_DEPRECATED и не выключение предупреждений приложения.
null означает «не задавали». В сериализованном представлении такие поля отсутствуют. Явный false сохраняется как false. Значение по умолчанию на сервере для этих флагов false, но происхождение настройки различается.
bsonSerialize возвращает stdClass с version,strict,deprecationErrors. Это описание PHP-объекта, не готовая команда с wire-полями apiVersion/apiStrict. Настройка подключается через Manager, а не вставляется вручную в каждую Query.
В драйвере2.5.5 ServerApi реализует MongoDB\BSON\Serializable, но не старый PHP Serializable, который всё ещё показан на просмотренной странице PHP.net. Текущий контракт подтверждён tagged stub/source. Не путайте BSON-сериализацию и пользовательский JSON-DTO.
Границы и ошибки
Stable API поддерживается MongoDB5.0+ и только в пределах заявленного набора команд и совместимого драйвера. Он не фиксирует схему ваших документов, время выполнения запросов, доступность сервера или поведение внешних библиотек. Unsupported версия2 намеренно отклоняется конструктором.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'sku'=>'MUG']]);
$default=new MongoDB\Driver\ServerApi(MongoDB\Driver\ServerApi::V1);
$explicit=new MongoDB\Driver\ServerApi(MongoDB\Driver\ServerApi::V1,false,false);
$strict=new MongoDB\Driver\ServerApi(MongoDB\Driver\ServerApi::V1,true,true);
$shapes=[];$rows=[];foreach(['По умолчанию'=>$default,'Явное false'=>$explicit,'Строгий API'=>$strict] as $label=>$api){$object=$api->bsonSerialize();$shapes[$label]=(array)$object;$rows[]=[$label,json_encode($object,JSON_THROW_ON_ERROR)];}
$apiManager=sr129ApiManager($settings,$strict);$apiServer=$apiManager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
$docs=sr129Query($apiServer,$namespace,['_id'=>1],['_id'=>0,'sku'=>1],1);$rows[]=['Чтение строгим клиентом',$docs[0]['sku']];
$invalid=false;try{new MongoDB\Driver\ServerApi('2');}catch(MongoDB\Driver\Exception\InvalidArgumentException){$invalid=true;}
$checks=['defaults_omit_null'=>$shapes['По умолчанию']===['version'=>'1'],'false_is_explicit'=>$shapes['Явное false']===['version'=>'1','strict'=>false,'deprecationErrors'=>false],'true_is_explicit'=>$shapes['Строгий API']===['version'=>'1','strict'=>true,'deprecationErrors'=>true],'returns_stdclass'=>$strict->bsonSerialize() instanceof stdClass,'typed_api_reads'=>$docs===[['sku'=>'MUG']],'unknown_version_rejected'=>$invalid];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-stable-config', ['Настройка / операция', 'Наблюдаемое представление'], $rows, $checks, $runtime);
echo 'mongodb129-server-stable-config: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-stable-config: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Сравните V1,null,false с V1,false,null. В первом объекте останется deprecationErrors:false, во втором strict:false. Явно выбирайте настройки, которые должен контролировать конфигурационный файл.
Отделить рабочие команды Stable API от диагностики вне API
После включения strict обычное чтение работает, а сбор версии сервера падает. Нужно понять причину и разделить рабочий контракт приложения и диагностический доступ.
Исходные данные
Один MUG qty4. Строгий Server взят из Manager с ServerApi(V1,true,true); обычный диагностический Server — из исходного Manager.
- Рабочие операции: find и count проходят через strict-клиент
- Граница API: buildInfo через тот же Server возвращает APIStrictError323
- Диагностика: обычный клиент получает версию; товар после отказа не изменился
Самый короткий полезный вызов
$api = new MongoDB\Driver\ServerApi(MongoDB\Driver\ServerApi::V1, true, true);
// Для Server, полученного от такого Manager:
// executeQuery(find) работает; executeCommand(buildInfo) даёт APIStrictError323.
// Не отключаем strict молча после ошибки: диагностика имеет отдельный клиент.Фрагмент выделяет текущую операцию. Полная программа ниже содержит подключение, создание данных, ограниченные чтения и очистку собственной лаборатории.
Что получится при выполнении
| Команда / проверка | Результат |
|---|---|
| find через строгий клиент | MUG |
| count через строгий клиент | 1 |
| buildInfo через строгий клиент | APIStrictError 323 |
| buildInfo через обычный клиент | true |
| Данные после отказа сохранены | true |
Пошаговый разбор
buildInfo не входит в Stable API V1 в проверенном сервере8.0.34. Поэтому отказ strict-клиента является ожидаемой проверкой контракта, а не доказательством, что база отключена.
Ловится конкретный CommandException с кодом323. Другие ошибки передаются выше. Не надо перехватывать всё подряд и повторять команду уже без strict: это незаметно отменяет выбранный договор приложения.
В примере диагностика использует отдельный заранее созданный обычный Manager. В реальном сервисе отделите этот маршрут по назначению и разрешениям. Возможности вне API не получают его гарантий совместимости.
Для deprecationErrors включён реальный флаг и выполнены разрешённые команды. Мы не объявляем любой устаревший синтаксис PHP серверной API-deprecation и не запускаем опасную историческую команду ради искусственного отказа.
Границы и ошибки
Это проверка конкретных команд в MongoDB8.0.34, а не сертификат всего приложения на Stable API. Нужен разбор используемых команд/опций и поддерживаемых версий. Успех count не означает, что следует пересчитывать огромную коллекцию на каждый HTTP-запрос.
Полная самостоятельная программа и архив
<?php
declare(strict_types=1);
require __DIR__.'/sr129-helper.php';
$settings=sr129Settings();$database=$settings['database'];
$manager=new MongoDB\Driver\Manager($settings['uri'],['serverSelectionTimeoutMS'=>1500,'connectTimeoutMS'=>500,'socketTimeoutMS'=>2000,'retryReads'=>false]);
$owned=[];
try{
$version=sr129Command($manager,$database,['buildInfo'=>1])[0]['version'];
if(version_compare($version,'8.0','<')){throw new RuntimeException('MongoDB8.0+ required');}
$server=$manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
if($server->getType()!==MongoDB\Driver\Server::TYPE_STANDALONE){throw new RuntimeException('Separate standalone lab required');}
$runtime=['php'=>PHP_VERSION,'extension'=>phpversion('mongodb'),'server'=>$version,'execution'=>'database','observed_host'=>$server->getHost(),'observed_port'=>$server->getPort()];
$namespace=sr129Create($manager,$database,$owned);$collection=$owned[0];
sr129Insert($manager,$namespace,[['_id'=>1,'sku'=>'MUG','qty'=>4]]);
$api=new MongoDB\Driver\ServerApi(MongoDB\Driver\ServerApi::V1,true,true);
$apiManager=sr129ApiManager($settings,$api);$apiServer=$apiManager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY));
$product=sr129Query($apiServer,$namespace,['_id'=>1],['_id'=>0,'sku'=>1,'qty'=>1],1)[0];
$count=sr129Rows($apiServer->executeReadCommand($database,new MongoDB\Driver\Command(['count'=>$collection,'query'=>['_id'=>1],'maxTimeMS'=>1500])))[0];
$errorCode=0;try{sr129Rows($apiServer->executeCommand($database,new MongoDB\Driver\Command(['buildInfo'=>1])));}catch(MongoDB\Driver\Exception\CommandException $error){$errorCode=$error->getCode();if($errorCode!==323){throw $error;}}
$normal=sr129Rows($server->executeCommand($database,new MongoDB\Driver\Command(['buildInfo'=>1])))[0];
$after=sr129Query($apiServer,$namespace,['_id'=>1],['_id'=>0,'sku'=>1,'qty'=>1],1)[0];
$rows=[['find через строгий клиент',$product['sku']],['count через строгий клиент',(int)$count['n']],['buildInfo через строгий клиент','APIStrictError '.$errorCode],['buildInfo через обычный клиент',isset($normal['version'])],['Данные после отказа сохранены',$after===$product]];
$checks=['stable_find_succeeds'=>$product===['sku'=>'MUG','qty'=>4],'stable_count_succeeds'=>(int)$count['n']===1,'strict_rejects_outside_api'=>$errorCode===323,'normal_diagnostics_allowed'=>isset($normal['version'])&&$normal['version']===$version,'data_unchanged'=>$after===$product];
}finally{
foreach(array_reverse($owned) as $name){sr129Command($manager,$database,['drop'=>$name],true);}
}
$removed=true;foreach($owned as $name){if(sr129Exists($manager,$database,$name)){$removed=false;}}
$checks['only_owned_collections_removed']=$removed && count($owned)===1;
sr129Report('mongodb129-server-strict-api', ['Команда / проверка', 'Результат'], $rows, $checks, $runtime);
echo 'mongodb129-server-strict-api: saved result.html and result.json
';
Ожидаемый результат
mongodb129-server-strict-api: saved result.html and result.json
Реальный запуск в собственной учебной MongoDB-коллекции. Результат показан в HTML и JSON. Helper и README входят в архив; неожиданные отказы не подменяются успешными строками.
Таблица фактического результата · JSON результата
Попробуйте изменить. Включите strict=false в отдельной копии: buildInfo сможет пройти, но теперь команды вне API разрешены. Объясните в конфигурации, почему выбран такой режим, вместо молчаливого fallback.
Полные контракты операций Server и настроек ServerApi
Здесь собраны новые карточки. Уже существующие getHost/getPort/getType/getServerDescription и другие методы диагностики сохраняют прежние адреса. Таблица типов узла и полный synopsis класса приведены в карточке Server.
| API | Задача |
|---|---|
| MongoDB\Driver\Server | Выполнить операцию на конкретном выбранном узле и связать её с наблюдаемым ответом. |
| MongoDB\Driver\Server::__construct | Понять происхождение Server и не создавать его через new. |
| MongoDB\Driver\Server::executeQuery | Получить ограниченную страницу документов на выбранном сервере. |
| MongoDB\Driver\Server::executeBulkWrite | Отправить подготовленные изменения одной коллекции. |
| MongoDB\Driver\Server::executeBulkWriteCommand | Отправить операции для разных коллекций через bulkWrite MongoDB8. |
| MongoDB\Driver\Server::executeCommand | Отправить низкоуровневую команду осознанно, с явными ожиданиями опций. |
| MongoDB\Driver\Server::executeReadCommand | Выполнить команду чтения и получить её ограниченный результат. |
| MongoDB\Driver\Server::executeReadWriteCommand | Прочитать исходные данные и сохранить результат командой. |
| MongoDB\Driver\Server::executeWriteCommand | Выполнить команду изменения структуры или состояния базы. |
| MongoDB\Driver\ServerApi | Объявить стабильный договор команд приложения при создании Manager. |
| MongoDB\Driver\ServerApi::__construct | Создать настройки версии API, strict и deprecationErrors. |
| MongoDB\Driver\ServerApi::bsonSerialize | Получить документ настроек и различить пропуск поля от false. |
Закрепить назначение запроса и его границы
Для своего запроса сначала определите нужные документы и поля, затем характер действия: чтение, запись или оба. Обычно Manager выбирает узел за приложение; если нужен конкретный Server, ответственность за выбор становится явной. Выберите подходящий execute-метод и наблюдаемый результат, а Stable API настройте как отдельный договор используемых возможностей.
Продолжение: Выбор серверов · Жизненный цикл Cursor · Результаты записи и понятная диагностика ошибок · Подтверждения и транзакции.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
MongoDB\Driver\ServerВыполнить операцию на конкретном выбранном узле и связать её с наблюдаемым ответом.
mongodb1.0.0 · mongodb
final class MongoDB\Driver\Server {
final private function __construct();
final public function executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $bulk, ?array $options = null): MongoDB\Driver\WriteResult;
final public function executeBulkWriteCommand(MongoDB\Driver\BulkWriteCommand $bulk, ?array $options = null): MongoDB\Driver\BulkWriteCommandResult;
final public function executeCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeQuery(string $namespace, MongoDB\Driver\Query $query, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeReadCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeReadWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function getHost(): string;
final public function getInfo(): array;
final public function getLatency(): ?int;
final public function getPort(): int;
final public function getServerDescription(): MongoDB\Driver\ServerDescription;
final public function getTags(): array;
final public function getType(): int;
final public function isArbiter(): bool;
final public function isHidden(): bool;
final public function isPassive(): bool;
final public function isPrimary(): bool;
final public function isSecondary(): bool;
}Выполнить операцию на конкретном выбранном узле и связать её с наблюдаемым ответом.
Сигнатура и параметры
final class MongoDB\Driver\Server {
final private function __construct();
final public function executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $bulk, ?array $options = null): MongoDB\Driver\WriteResult;
final public function executeBulkWriteCommand(MongoDB\Driver\BulkWriteCommand $bulk, ?array $options = null): MongoDB\Driver\BulkWriteCommandResult;
final public function executeCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeQuery(string $namespace, MongoDB\Driver\Query $query, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeReadCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeReadWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function executeWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor;
final public function getHost(): string;
final public function getInfo(): array;
final public function getLatency(): ?int;
final public function getPort(): int;
final public function getServerDescription(): MongoDB\Driver\ServerDescription;
final public function getTags(): array;
final public function getType(): int;
final public function isArbiter(): bool;
final public function isHidden(): bool;
final public function isPassive(): bool;
final public function isPrimary(): bool;
final public function isSecondary(): bool;
}| Вход / часть API | Смысл |
|---|---|
| Получение | Manager::selectServer/getServers или Cursor::getServer; не new Server |
| Тип | final-класс; операции привязаны к этому узлу |
| Константы | Полный перечень типов сервера приведён ниже; это сведения о топологии, не разрешения на запись |
Что получает вызывающий код
Объект Server содержит ссылку на конкретный сервер Manager. Методы запросов/команд возвращают Cursor, методы пакетов — соответствующий результат записи. Диагностические getters сохраняют свои ранее созданные карточки.
Ошибки и ограничения вызова
Private-конструктор недоступен. Выбор узла может отказать до операции, а связь/авторизация/команда — во время неё. Наличие Server не гарантирует постоянную доступность или способность выполнять запись.
Версии
Класс с mongodb1.0.0; read/write command-методы с1.4.0; TYPE_LOAD_BALANCER с1.11.0; executeBulkWriteCommand с2.1.0 и MongoDB8.0. Исторические object-options заменены массивами в2.0.
| Константа Server | Значение | Смысл |
|---|---|---|
| TYPE_UNKNOWN | 0 | Тип пока неизвестен |
| TYPE_STANDALONE | 1 | Отдельный сервер |
| TYPE_MONGOS | 2 | Маршрутизатор mongos |
| TYPE_POSSIBLE_PRIMARY | 3 | Возможный primary по сведениям другого участника, ещё не проверенный |
| TYPE_RS_PRIMARY | 4 | Primary replica set |
| TYPE_RS_SECONDARY | 5 | Secondary replica set |
| TYPE_RS_ARBITER | 6 | Арбитр replica set |
| TYPE_RS_OTHER | 7 | Другой участник, например запускающийся/recovering/hidden; запросы недоступны, сведения о хостах могут помогать обнаружению |
| TYPE_RS_GHOST | 8 | Неинициализированный/удалённый или временно неготовый участник; запросы и hostlist для обнаружения недоступны |
| TYPE_LOAD_BALANCER | 9 | Балансировщик; константа с1.11.0 |
Существующие карточки getHost/getPort/getType и описаний сервера.
Два практических применения
Связать товар с ответившим узлом
Cursor::getServer сравнивается с выбранным endpoint; реальный MUG подтверждает, что выполнен запрос.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Выполнить чтение и сохранение отчёта на выбранном узле
Server запускает aggregate+$merge; отдельный Query показывает350, затем400 в своей коллекции.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
ReadPreference не перевыбирает сервер внутри его execute-методов. Роль узла может измениться, поэтому не кэшируйте Server как вечную гарантию primary. Для обычного приложения часто достаточно Manager/библиотеки; конкретный Server нужен для осознанного управления и диагностики.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::__constructПонять происхождение Server и не создавать его через new.
mongodb1.0.0 · mongodb
final private function MongoDB\Driver\Server::__construct()Понять происхождение Server и не создавать его через new.
Сигнатура и параметры
final private function MongoDB\Driver\Server::__construct()Параметров нет.
Что получает вызывающий код
Пользовательский вызов не предусмотрен. Server создаётся драйвером при работе Manager с соединением; selectServer и getServers предоставляют эти объекты. Конструктор не принимает URI или другие параметры.
Ошибки и ограничения вызова
new MongoDB\Driver\Server() вызывает PHP Error из-за private. Ошибка selectServer при отсутствии подходящего узла относится к Manager; не маскируйте её пустым объектом Server.
Версии
С mongodb1.0.0. Современный путь остаётся Manager → Server; старые примеры с публичным new к этому классу не применяются.
Два практических применения
Получить узел для диагностического запроса
selectServer возвращает рабочий Server, а попытка new отдельно показывает ожидаемый запрет.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Получить Server с настройками Stable API
Server выбирается из специально настроенного Manager; таким образом его запросы получают договор API, а не выдуманные аргументы new Server.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Не обходите private через reflection/unserialize. Адрес выбирается в Manager, а не в конструкторе Server. Список getServers не заменяет проверку пригодности узла для конкретной операции.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeQueryПолучить ограниченную страницу документов на выбранном сервере.
mongodb1.0.0 · mongodb
final public function MongoDB\Driver\Server::executeQuery(string $namespace, MongoDB\Driver\Query $query, ?array $options = null): MongoDB\Driver\CursorПолучить ограниченную страницу документов на выбранном сервере.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeQuery(string $namespace, MongoDB\Driver\Query $query, ?array $options = null): MongoDB\Driver\Cursor| Вход / часть API | Смысл |
|---|---|
| namespace | Полное имя база.коллекция |
| query | Query с условием, projection, sort, limit и другими параметрами чтения |
| options.readPreference | ReadPreference; не перенаправляет на другой Server |
| options.session | Session этой операции |
| options=null | Пустые опции; readPreference и readConcern объекта Query по умолчанию определяются активной транзакцией, затем URI |
Что получает вызывающий код
Cursor выбранных документов. Пустой результат означает отсутствие совпадений, а не ошибку соединения. Данные извлекаются из Cursor; toArray разумен только для ограниченного результата.
Ошибки и ограничения вызова
ConnectionException — ошибка связи, кроме авторизации; AuthenticationException — отказ авторизации; InvalidArgumentException — неверные аргументы/опции. Остальные отказы команды или запроса относятся к RuntimeException и её специализированным подклассам. Сетевой отказ не является пустым успешным результатом.
Версии
С mongodb1.0.0; массив options с1.4.0. Передача отдельного объекта вместо options объявлена устаревшей в1.21.0 и удалена в2.0.0. Ранее третьим аргументом мог быть ReadPreference; в2.x требуется массив/null.
Два практических применения
Показать каталог без скрытых полей
Сервер вернул2нужных товара через projection/sort/limit; чужой tenant и черновик исключены.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Продолжить выдачу по ключу
Следующая пара price/_id возвращает Чайник, без загрузки предыдущих страниц в PHP.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена. readConcern задаётся в Query, не как произвольная опция Server::executeQuery.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeBulkWriteОтправить подготовленные изменения одной коллекции.
mongodb1.0.0 · mongodb
final public function MongoDB\Driver\Server::executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $bulk, ?array $options = null): MongoDB\Driver\WriteResultОтправить подготовленные изменения одной коллекции.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $bulk, ?array $options = null): MongoDB\Driver\WriteResult| Вход / часть API | Смысл |
|---|---|
| namespace | Один полный namespace база.коллекция |
| bulk | BulkWrite с действиями в этой коллекции |
| options.session | Session; нельзя совмещать с w=0 |
| options.writeConcern | WriteConcern; по умолчанию активная транзакция, затем URI |
| options=null | Без явного переопределения опций |
Что получает вызывающий код
WriteResult с подтверждёнными итогами вставок/изменений/удалений. Драйвер группирует однотипные операции для сокращения обменов; один BulkWrite не обещает один сетевой запрос.
Ошибки и ограничения вызова
InvalidArgumentException: пустой или уже выполненный BulkWrite, неправильные аргументы, session вместе с неподтверждаемой записью. BulkWriteException: ошибка записи или подтверждения; прочие отказы могут быть RuntimeException. ConnectionException/AuthenticationException сохраняют отдельный смысл.
Версии
С mongodb1.0.0; массив options с1.4.0. Передача отдельного объекта вместо options объявлена устаревшей в1.21.0 и удалена в2.0.0. Пустой пакет с1.3.0 вызывает InvalidArgumentException (раньше BulkWriteException); запрет session+w=0 уточнён в1.4.4.
Два практических применения
Изменить остаток без чтения всего каталога
Точный _id и qty>=2 защищают $inc: MUG5→3, matched/modified=1.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Обновить состав каталога
Тот же пакет добавляет PLATE и удаляет DRAFT, а итоговая таблица показывает оставшиеся позиции.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Объект пакета одноразовый. Частичный успех не откатывается автоматически; повтор требует анализа результата и идемпотентности. Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeBulkWriteCommandОтправить операции для разных коллекций через bulkWrite MongoDB8.
mongodb2.1.0; MongoDB8.0+ · mongodb
final public function MongoDB\Driver\Server::executeBulkWriteCommand(MongoDB\Driver\BulkWriteCommand $bulk, ?array $options = null): MongoDB\Driver\BulkWriteCommandResultОтправить операции для разных коллекций через bulkWrite MongoDB8.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeBulkWriteCommand(MongoDB\Driver\BulkWriteCommand $bulk, ?array $options = null): MongoDB\Driver\BulkWriteCommandResult| Вход / часть API | Смысл |
|---|---|
| bulk | BulkWriteCommand с namespace внутри каждой операции |
| options.session | Session; нельзя совмещать с w=0 |
| options.writeConcern | WriteConcern; по умолчанию активная транзакция, затем URI |
| options=null | Без явного переопределения опций |
Что получает вызывающий код
BulkWriteCommandResult с подтверждёнными итогами вставок/изменений/удалений. Команда может включать разные namespace, но не становится общей транзакцией.
Ошибки и ограничения вызова
InvalidArgumentException: пустой или уже выполненный BulkWriteCommand, неправильные аргументы, session вместе с неподтверждаемой записью. BulkWriteCommandException: отказ команды, отдельной записи или write concern. ConnectionException/AuthenticationException сохраняют отдельный смысл.
Версии
С mongodb2.1.0; требуется MongoDB8.0+.
Два практических применения
Создать запись каталога
insertOne получает namespace каталога и сохраняет MUG qty4.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Записать событие импорта
Вторая операция того же пакета использует namespace журнала и сохраняет catalog-import. Чтение подтверждает обе записи.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Объект пакета одноразовый. Частичный успех не откатывается автоматически; повтор требует анализа результата и идемпотентности. Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeCommandОтправить низкоуровневую команду осознанно, с явными ожиданиями опций.
mongodb1.0.0 · mongodb
final public function MongoDB\Driver\Server::executeCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\CursorОтправить низкоуровневую команду осознанно, с явными ожиданиями опций.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor| Вход / часть API | Смысл |
|---|---|
| db | Имя базы, не полный namespace |
| command | MongoDB\Driver\Command с документом команды |
| options.session | Session операции |
| options.readConcern | ReadConcern (поддержка сервером3.2+; более старый сервер откажет) |
| options.readPreference | ReadPreference; не перевыбирает Server |
| options.writeConcern | WriteConcern подтверждения записи |
Что получает вызывающий код
Cursor результата команды; форма документов зависит от самой команды. Не применяет специальную логику. Настройки concern/readPreference наследуются из активной транзакции; вне неё URI-настройки не подставляются, используется первичный режим.
Ошибки и ограничения вызова
ConnectionException — ошибка связи, кроме авторизации; AuthenticationException — отказ авторизации; InvalidArgumentException — неверные аргументы/опции. Остальные отказы команды или запроса относятся к RuntimeException и её специализированным подклассам. Сетевой отказ не является пустым успешным результатом. При активной транзакции session нельзя отдельно передавать readConcern/writeConcern в опциях операции: они задаются при старте транзакции, иначе InvalidArgumentException. Session с неподтверждаемой записью также недопустима там, где операция пишет.
Версии
С mongodb1.0.0; массив options с1.4.0. Передача отдельного объекта вместо options объявлена устаревшей в1.21.0 и удалена в2.0.0. Ранее third-argument ReadPreference; в1.4.4 уточнён запрет session+w=0.
Два практических применения
Проверить ответ выбранного узла
ping отвечает отдельно от предметного отчёта; успешный ping не подменяет права и чтение заказов.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Разобрать границу API диагностики
buildInfo с обычным клиентом работает, со strict-клиентом даёт323. Ошибку не скрывает автоматический fallback.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена. Выбирайте специализированный read/write метод, когда известен характер команды.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeReadCommandВыполнить команду чтения и получить её ограниченный результат.
mongodb1.4.0 · mongodb
final public function MongoDB\Driver\Server::executeReadCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\CursorВыполнить команду чтения и получить её ограниченный результат.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeReadCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor| Вход / часть API | Смысл |
|---|---|
| db | Имя базы, не полный namespace |
| command | MongoDB\Driver\Command с документом команды |
| options.session | Session операции |
| options.readConcern | ReadConcern (поддержка сервером3.2+; более старый сервер откажет) |
| options.readPreference | ReadPreference; не перевыбирает Server |
Что получает вызывающий код
Cursor результата команды; форма документов зависит от самой команды. Применяет правила чтения; readPreference и readConcern по умолчанию берутся из активной транзакции, затем URI.
Ошибки и ограничения вызова
ConnectionException — ошибка связи, кроме авторизации; AuthenticationException — отказ авторизации; InvalidArgumentException — неверные аргументы/опции. Остальные отказы команды или запроса относятся к RuntimeException и её специализированным подклассам. Сетевой отказ не является пустым успешным результатом. При активной транзакции session нельзя отдельно передавать readConcern/writeConcern в опциях операции: они задаются при старте транзакции, иначе InvalidArgumentException. Session с неподтверждаемой записью также недопустима там, где операция пишет.
Версии
С mongodb1.4.0. Для write/readwrite в1.4.4 уточнён отказ session вместе с неподтверждаемой записью. Используйте современные массивы options.
Два практических применения
Получить сумму выбранного магазина
aggregate исключает черновик и чужой магазин до группировки:2заказа,350.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Проверить созданное правило
listIndexes возвращает фактический sku_unique с unique=true; это подтверждение, что подготовка действительно создала индекс.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена. Команда чтения не гарантирует согласованный снимок нескольких последующих операций.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeReadWriteCommandПрочитать исходные данные и сохранить результат командой.
mongodb1.4.0 · mongodb
final public function MongoDB\Driver\Server::executeReadWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\CursorПрочитать исходные данные и сохранить результат командой.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeReadWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor| Вход / часть API | Смысл |
|---|---|
| db | Имя базы, не полный namespace |
| command | MongoDB\Driver\Command с документом команды |
| options.session | Session операции |
| options.readConcern | ReadConcern (поддержка сервером3.2+; более старый сервер откажет) |
| options.writeConcern | WriteConcern подтверждения записи |
Что получает вызывающий код
Cursor результата команды; форма документов зависит от самой команды. Применяет правила команды чтения с записью; readConcern/writeConcern по умолчанию определяются активной транзакцией, затем URI.
Ошибки и ограничения вызова
ConnectionException — ошибка связи, кроме авторизации; AuthenticationException — отказ авторизации; InvalidArgumentException — неверные аргументы/опции. Остальные отказы команды или запроса относятся к RuntimeException и её специализированным подклассам. Сетевой отказ не является пустым успешным результатом. При активной транзакции session нельзя отдельно передавать readConcern/writeConcern в опциях операции: они задаются при старте транзакции, иначе InvalidArgumentException. Session с неподтверждаемой записью также недопустима там, где операция пишет.
Версии
С mongodb1.4.0. Для write/readwrite в1.4.4 уточнён отказ session вместе с неподтверждаемой записью. Используйте современные массивы options.
Два практических применения
Сохранить вычисленный отчёт
aggregate+$merge создаёт запись A с2заказами и350; отдельное чтение показывает её.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Обновить отчёт после изменения заказа
Повторная команда заменяет запись A на400 без дубликата; отсутствующие группы сами не удаляются.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена. Пустой Cursor после $merge означает отсутствие возвращаемых документов; сохранённый результат читается отдельно.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\Server::executeWriteCommandВыполнить команду изменения структуры или состояния базы.
mongodb1.4.0 · mongodb
final public function MongoDB\Driver\Server::executeWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\CursorВыполнить команду изменения структуры или состояния базы.
Сигнатура и параметры
final public function MongoDB\Driver\Server::executeWriteCommand(string $db, MongoDB\Driver\Command $command, ?array $options = null): MongoDB\Driver\Cursor| Вход / часть API | Смысл |
|---|---|
| db | Имя базы, не полный namespace |
| command | MongoDB\Driver\Command с документом команды |
| options.session | Session операции |
| options.writeConcern | WriteConcern подтверждения записи |
Что получает вызывающий код
Cursor результата команды; форма документов зависит от самой команды. Применяет правила записи; writeConcern по умолчанию определяется активной транзакцией, затем URI.
Ошибки и ограничения вызова
ConnectionException — ошибка связи, кроме авторизации; AuthenticationException — отказ авторизации; InvalidArgumentException — неверные аргументы/опции. Остальные отказы команды или запроса относятся к RuntimeException и её специализированным подклассам. Сетевой отказ не является пустым успешным результатом. При активной транзакции session нельзя отдельно передавать readConcern/writeConcern в опциях операции: они задаются при старте транзакции, иначе InvalidArgumentException. Session с неподтверждаемой записью также недопустима там, где операция пишет.
Версии
С mongodb1.4.0. Для write/readwrite в1.4.4 уточнён отказ session вместе с неподтверждаемой записью. Используйте современные массивы options.
Два практических применения
Подготовить уникальный артикул
createIndexes задаёт sku_unique; реальная попытка дубля получает11000.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Повторить одинаковую подготовку
Второе создание того же определения успешно, индекс и два исходных товара сохраняются.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Операция остаётся на этом Server. readPreference в допустимых опциях влияет на протокол secondary/mongos, но не выбирает другой узел. При записи вызывающий код должен выбрать сервер, способный писать; обычная запись в secondary не разрешена. Для insert/update/delete используйте executeBulkWrite; этот command-метод для них не предназначен.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\ServerApiОбъявить стабильный договор команд приложения при создании Manager.
mongodb1.10.0 · mongodb
final class MongoDB\Driver\ServerApi implements MongoDB\BSON\Serializable {
public const V1 = '1';
final public function __construct(string $version, ?bool $strict = null, ?bool $deprecationErrors = null);
final public function bsonSerialize(): stdClass;
}Объявить стабильный договор команд приложения при создании Manager.
Сигнатура и параметры
final class MongoDB\Driver\ServerApi implements MongoDB\BSON\Serializable {
public const V1 = '1';
final public function __construct(string $version, ?bool $strict = null, ?bool $deprecationErrors = null);
final public function bsonSerialize(): stdClass;
}| Вход / часть API | Смысл |
|---|---|
| V1 | Строка1; единственная поддерживаемая версия API в текущем драйвере |
| Назначение | Объект передаётся как driverOptions.serverApi в Manager |
| Текущий интерфейс | MongoDB\BSON\Serializable; старый PHP Serializable в synopsis PHP.net не соответствует драйверу2.5.5 |
Что получает вызывающий код
Объект настроек API, который применяется Manager к операциям. Это не подключение и не версия сервера. bsonSerialize даёт представление настроек; полезный эффект подтверждается реальным разрешённым запросом и ожидаемым strict-отказом.
Ошибки и ограничения вызова
Неподдерживаемая версия вызывает InvalidArgumentException в проверенном2.5.5. Серверные ошибки совместимости приходят при выполнении операции; конструктор не проверяет сеть и доступность базы.
Версии
Класс с mongodb1.10.0; Stable API введён MongoDB5.0. Сверенная текущая форма2.5.5 подтверждена официальными tagged stub/source. Дополнительные PHP-механизмы __serialize/__unserialize/__set_state видны в stub, но не заменяют настройку Manager или BSON-контракт.
Два практических применения
Проверить фактическую конфигурацию
Три формы показывают различие null/false/true; strict-клиент читает MUG.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Найти команду за пределами договора
find/count проходят, buildInfo отклоняется323, обычная диагностика выделена отдельно.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Гарантия касается поддерживаемого набора команд/опций и совместимого драйвера. Она не фиксирует вашу схему, индексы, производительность или доступность. Команды вне API требуют отдельного решения, а не молчаливого отключения strict.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\ServerApi::__constructСоздать настройки версии API, strict и deprecationErrors.
mongodb1.10.0 · mongodb
final public function MongoDB\Driver\ServerApi::__construct(string $version, ?bool $strict = null, ?bool $deprecationErrors = null)Создать настройки версии API, strict и deprecationErrors.
Сигнатура и параметры
final public function MongoDB\Driver\ServerApi::__construct(string $version, ?bool $strict = null, ?bool $deprecationErrors = null)| Вход / часть API | Смысл |
|---|---|
| version | Поддерживаемая версия; используйте ServerApi::V1 |
| strict=null | Не задан; серверный default false. true запрещает команды/возможности вне версии API |
| deprecationErrors=null | Не задан; серверный default false. true отклоняет deprecated возможности именно данного API |
| Передача в Manager | Третий аргумент: ["serverApi" => $api]; не произвольный ключ Query |
Что получает вызывающий код
new возвращает ServerApi. Сам конструктор не отправляет команду. Только Manager, созданный с этим объектом, использует настройки для последующих операций.
Ошибки и ограничения вызова
В2.5.5 неизвестная версия вроде2 даёт InvalidArgumentException; неверные PHP-типы/разбор аргументов также отклоняются. Ошибка строгой серверной команды возникает позже и не означает отказ конструктора.
Версии
С mongodb1.10.0, серверная Stable API MongoDB5.0+. Nullable-флаги отличаются от явно переданного false в сериализованном описании.
Два практических применения
Задать и проверить осознанные defaults
V1 без флагов оставляет их незаданными, V1,false,false явно сохраняетfalse; вывод показывает обе формы.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Ограничить приложение стабильными командами
V1,true,true разрешает чтение товара и намеренно отказывает диагностическому buildInfo.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
deprecationErrors не лечит PHP E_DEPRECATED и несовместимость Composer-пакета с расширением. strict не является режимом авторизации или валидации схемы документов.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
MongoDB\Driver\ServerApi::bsonSerializeПолучить документ настроек и различить пропуск поля от false.
mongodb1.10.0 · mongodb
final public function MongoDB\Driver\ServerApi::bsonSerialize(): stdClassПолучить документ настроек и различить пропуск поля от false.
Сигнатура и параметры
final public function MongoDB\Driver\ServerApi::bsonSerialize(): stdClassПараметров нет.
Что получает вызывающий код
stdClass для BSON-сериализации: version и только заданные strict/deprecationErrors. В2.5.5 незаданные/null-поля отсутствуют, false сохраняется. Это PHP-объект, не JSON-текст; json_encode отдельно даёт понятную диагностическую строку.
Ошибки и ограничения вызова
Параметров нет; официальная страница указывает InvalidArgumentException при ошибке разбора аргументов. Ошибки json_encode и выполнения команд имеют собственный контракт.
Версии
С mongodb1.10.0. Точная структура текущей версии сверена tagged исходником2.5.5 и реальным probe. Названия version/strict/deprecationErrors не совпадают с wire-полями apiVersion/apiStrict/apiDeprecationErrors.
Два практических применения
Выявить настройку, оставленную по умолчанию
В первом документе только version:1, поэтому unset и false можно различить при диагностике.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Подтвердить явно включённый строгий договор
Третий документ содержит обаtrue; тот же объект подключён к Manager и используется для реального чтения MUG.
Короткий вызов, исходные данные, полная программа и результат · Таблица реального запуска
Границы и продолжение
Не добавляйте результат напрямую к произвольной команде и не считайте его удалённым отчётом сервера. Это представление локального объекта настроек. Для применения передайте ServerApi в Manager.
Выбор узла и диагностика Server · Manager, Query, BulkWrite · Чтение Cursor · Общая атомарность и транзакции.
Источники и обсуждения
- MongoDB\Driver\Server
- MongoDB\Driver\Server::__construct
- MongoDB\Driver\Server::executeQuery
- MongoDB\Driver\Server::executeBulkWrite
- MongoDB\Driver\Server::executeBulkWriteCommand
- MongoDB\Driver\Server::executeCommand
- MongoDB\Driver\Server::executeReadCommand
- MongoDB\Driver\Server::executeReadWriteCommand
- MongoDB\Driver\Server::executeWriteCommand
- MongoDB\Driver\ServerApi
- MongoDB\Driver\ServerApi::__construct
- MongoDB\Driver\ServerApi::bsonSerialize
- Текущий исходник ServerApi
- Текущий stub ServerApi
- Stable API MongoDB8.0
- Сохранение отчёта через merge
- Операция insertOne внутри команды
- Подтверждённое число вставок
- Современная ReadPreference
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


