ZF2 + Doctrine ODM: Indexes and Replica Sets

The first installment of ZF2 + Doctrine Integration covered some basic setup and configuration instruction, as well as why you may want to use Mongo in your ZF2 application. This post will focus more on some of the more advanced (but still crucially important) aspects of Doctrine ODM, configuring indexes and replica sets.

What to Index

Indexes in Mongo are very trivial to setup (just like in MySQL), but the consequences of your indexes are very difficult to determine at the beginning. If you look at the Mongo Indexes Documentation, you’ll learn about indexes contributing to search speed, and also covering queries. Index covered queries are queries where the search fields are the projected return; Mongo does not need to read the documents to return data. These queries are going to be very fast and efficient…but wait! Being an ODM, Doctrine doesn’t give us the nice support to project only certain fields. This basically means that you can’t perform covered queries. An exception is the query builder API, but then you aren’t working with managed objects and there are quirks to projected persists. 

Going with this, the only thing you can reliably count on is covering all of your query search terms with indexes. The easiest way to do this is by looking at a mapping class, and then indexing anything that is in a findBy clause (don’t give direct access to ObjectRepository find by in your mapper). Indexes are easy to declare in code. Let’s look at an example:

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/** 
 * @ODM\Field(type="string") 
 * @ODM\Index()
 */
 public $association;

This represents a single query single field index. This type of index is great if you won’t be querying on any fields other than “association” (in this case). However, let’s say I also query on a field “type” or also the combination of “association, type”. This will be much better served using a compound index. These are also easy to create, but must be annotated at the document level. In the above example, the index is annotated at the field level. In the below example, the annotation occurs on the class.

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/**
 * @ODM\Document(collection="sample")
 * @ODM\UniqueIndex(keys={"association"="asc", "type"="asc"})
 */
class Sample

Now, a compound index is created and it is unique.  I could also generate a non-unique index by using @ODM\Index instead.

Although we have defined indexes, they are not created in the database. In order to do this, we must use the SchemaManager to create the “schema” for us. Luckily there is a console tool for doing this. Before doing so, however, you must create the entity paths so the schema manager can resolve where the entities are located (it’s not a wizard). The doctrine['driver']['ODM_Driver'] entry is what you need in both Demo and DemoBase configs.From the root of your project, perform the following:

./vendor/bin/doctrine-module odm:schema:create

Now that you see how easy it is to index in Doctrine ODM, there’s no reason to not index all of your queries!

Replica Sets

Another important (and under documented) feature to use when moving your application to a production environment is setting up replica sets. I won’t go to far into the details of how to actually set it up, as it is done very well already in the Replica Set Documentation. I have a 2 member replica set with an arbiter. The 2 members are off of the application server, and the arbiter is on the application server; this is a very common setup for lightweight applications.

Whenever the replica set is setup, the hosts of the mongod instances in the set will be something like mongo1.host.com, mongo2.host.com. These addresses should not be in public dns, and should instead be in the /etc/hosts file of all of your mongo instances and application server. This means that mongo1.host.com and mongo2.host.com are accessible from your application server. You can then make an edit to your doctrine config file. You can utilize Mongo’s connection string in order to connect to the replica set. It will look something like:

$connectionString = "mongodb://mongo1.host.com:27017,mongo2.host.com:27017/dbname?replicaSet=replicaSetName";

This connection string can be passed into Doctrine’s configuration file. You can check out a working config file here. It’s that easy! The PHP driver is replica set aware and will handle all of the details for you!

Keep an eye out for more installments about integrating ZF2 and Doctrine ODM!

Categories: Uncategorized

Leave a Reply