Migration from mongo PHP extension to mongodb extension

In this article I’ll describe my experience of migration from mongo PHP extension to mongodb. This two extensions have totally different API. So we need some high-level abstraction for the new one. I use MongoDB PHP Library. It has API similar to old driver. Docs for this library has upgrade guide, but without examples. Also there are a lot of small differences that can cause a lot of bugs. Here they are:

1. Connection.

Now connection will look like:

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

If you need authentication (add urlencode for your password):

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

In options replica and auth will not work.

2. Check all mongo extension objects.

Use $db->collectionName instead of new \MongoCollection($db, ‘collectionName’).

\MongoRegex is now \MongoDB\BSON\Regex and has different parameters. \MongoId is now \MongoDB\BSON\ObjectID.

This is the most commonly used classes. If you use something else check for analogs in docs.

3. find\findOne.

Now instead of array it will return \MongoDB\Model\BSONDocument object. At first look it works like an array. But you should be careful. Because if you have in your code things like is_array(), array_merge() etc it will not work with this object. Second parameter is options. If you want to set a list of fields to return add projection into options:

$collection->find([], [‘projection’ => [‘id’, ‘name’, ‘email’]])

There is no methods limit(), offset(), skip(), order(), nextOne() in new library. Instead of using methods add parameters into options array. Example:

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

Count also doesn’t work with cursor. You can use only

$collection->count() not $collection->find()->count().

4. Update.

There are a lot of new methods for this. And sometimes their behavior is not obvious. I choose this three:

updateOne([‘name’ => ‘foo’], [‘$set’ => [‘title’ => ‘test’, ...]]) – if you need to update only part of an object. Setting ‘_id’ here will cause fatal error.

findOneAndReplace([‘name’ => ‘foo’], $fullObject) – if you want to rewrite full object. ‘_id’ must be an object, not string.

updateMany([‘name’ => ‘foo’], [‘$set’ => [‘title’ => ‘test’, ...]]) – works like updateOne.

All this methods will not return updated object as it was in old lib, they will return MongoDB\UpdateResult.

5. Other.

Insert was changed into insertOne and returns MongoDB\InsertOneResult. Results format in aggregate() method was changed. Some methods were just renamed, like remove(), insertMany(). Check upgrade guide for another changes.