Переход с расширения mongo на mongodb для PHP

Этой статье я расскажу о своем опыте миграции с устаревшего mongo PHP extension на mongodb. Расширения имеют абсолютно разный API. Поэтому есть смысл применить для нового более высокоуровневую абстракцию.

Я для этой цели использовал MongoDB PHP Library. У этой библиотеки API достаточно близок к старой версии. В документации есть upgrade guide, но без примеров. При этом есть куча мелких отличий, которые, в свою очередь, чреваты кучей багов. Ниже перечислю основные, из тех с которыми пришлось столкнуться:

1. Подключение.

Теперь подключение выглядит так:

$client = new \MongoDB\Client(
    'mongodb://rs1.example.com,rs2.example.com/?replicaSet=myReplicaSet',
    [
        'readPreference' => 'secondaryPreferred'
    ]
);

C аутентификацией (для пароля нужно добавить urlencode):

 mongodb://username:[email protected],rs2.example.com/

Если указать реплику и аутентификацию в параметрах (как было раньше) — работать не будет.

2. Объекты от старого расширения.

Используйте $db->collectionName вместо new \MongoCollection($db, ‘collectionName’).
\MongoRegex меняется на \MongoDB\BSON\Regex и принимает другие параметры на вход.
\MongoId заменен на \MongoDB\BSON\ObjectID.
Это наиболее часто используемые классы. Если используется что то еще — ищите аналоги в документации.

3. Методы find\findOne.

Теперь вместо массива будет возвращаться объект \MongoDB\Model\BSONDocument. На первый взгляд он может работать так же как массив. Но тут нужно быть осторожным. Потому что если в старом коде используется что то типа is_array(), array_merge() и т.д., в применении к такому объекту, работать это не будет.
Второй параметр теперь options. Если нужно задать список возвращаемых полей, используйте параметр projection в options:
$collection->find([], [‘projection’ => [‘id’, ‘name’, ‘email’]])
В новой библиотеке нет методов limit(), offset(), skip(), order(), nextOne(). Вместо использования методов добавляейте эти параметры в options. Например:

$collection->find([], [
    'skip' => 10,
    'limit' => 10,
    'sort' => [‘name’ => -1]
]);

*Строка в параметре limit теперь вызовет fatal error.
Так же, теперь нельзя применить метод count к курсору. Можно использовать 
$collection->count(), но не $collection->find()->count().

4. Метод update.

Теперь для этой цели много новых методов. И как с ними работать далеко не всегда очевидно.
Для себя я выбрал три:
updateOne([‘name’ => ‘foo’], [‘$set’ => [‘title’ => ‘test’, ...]]) — если нужно обновить только часть объекта. Переданный параметр ‘_id’ вызовет fatal error.
findOneAndReplace([‘name’ => ‘foo’], $fullObject) — если нужно переписать объект целиком. ‘_id’ должен быть объектом, не строкой.
updateMany([‘name’ => ‘foo’], [‘$set’ => [‘title’ => ‘test’, ...]]) — работает аналогично с updateOne.
Все эти методы возвращают MongoDB\UpdateResult, а не обновленный объект, как было раньше.

5. Остальное.

Некоторые методы были просто переименованы, например remove(), insertMany(). Практически во всех методах поменялись возвращаемые параметры.
Insert был заменен на insertOne и возвращает MongoDB\InsertOneResult.
Формат результатов в методе aggregate() был изменен.
Смотрите upgrade guide насчет других изменений.