What Makes A Driver?

Often, we use the word “Driver” without defining what we mean. An application wishing to use MongoDB can be in any coding language. However, once it wants to connect to a database, it needs some kind of translation layer that knows both the language of the application and the language of the database. This layer is the Driver.

The fact that MongoDB fosters development in a diverse set of languages is especially important for the wide-spread adoption of the database. Drivers allow application developers to easily interact with the database without learning another language.

What Does A Driver Do?

Primarily, a driver is the layer that allows an application to send and retrieve data from MongoDB. It has six main responsibilities:

  1. Provides abstractions of server elements, such as collections, databases, cursors, replica set nodes, and mongos instances.

    For example, when you query MongoDB, a cursor is created on the server and the application retrieves the first batch of results. As the application iterates over these results, it may have to send a message back to the server to get a subsequent batch to retrieve more results. The driver has a representation of the cursor so that it can allow the application code to iterate over results, can manage the retrieval of batches of results, and can know where to send the close cursor message.

  2. Handles serialization and deserialization of native language types and data structures into BSON elements.

    BSON is the data format used by MongoDB, and there is a specific mapping from native language types to the different BSON types.

    Additionally, each language can use a particular data structure as the application-side representation of a MongoDB document, such as hashes in Ruby. The Ruby driver handles serializing a Ruby hash into a BSON document and each of the types (String, Integer, Symbol, Array, etc.) into their corresponding BSON types.

  3. Handles the sending and receiving of messages over sockets according to the wire protocol.

    The wire protocol is the set of rules regarding the structure and types of messages transmitted between an application and MongoDB. For instance, for the GetMore messages, the wire protocol specifies the format of the message, which includes the collection namespace, the number of documents to return, and the cursor ID.

  4. Implements connection pooling.

    All drivers support TCP socket pooling for use in multi-threaded applications. The drivers bind threads to sockets so that the application would never risk being unable to read its own writes in a replica set. This means that in a single thread, the same socket is checked out and used. If there is a connection failure, the driver ensures that the thread connects to the same node for the above reasons.

  5. Monitors node state.

    A driver keeps track of MongoDB node states and updates its view of the nodes state upon change. In the case of a replica set, the driver will cache information about the nodes and handle refreshing its cached view if a new primary is elected during a “failover”. The monitoring also allows drivers to handle operation routing.

  6. Routes operations according to Read Preferences.

    The driver handles operation-routing such that a user can specify a read preference, for example, a user can specify to read from a primary or a secondary.

    In the case of a sharded cluster, the driver talks to one or multiple mongos routers and handles load balancing.

How is a Driver Different from an ODM?

Many people often confuse an ODM (Object Document Mapper) and a driver. These are two completely different libraries.

The ODM is the layer of code in between the application and the driver. The ODM layer allows more advanced mapping between application objects and database objects.

The ODM allows the programmer to define relationships between classes at a higher level than a driver and interact with the documents using this extra logic. ODMs typically have a dependency on a driver for handling all the lower-level network layer code.

For an example of an ODM, see Mongoid which is an ODM for Ruby.

Do Drivers Have a Common Architecture?

The architecture of each driver is different for a number of reasons.

Many of the drivers started out as open source projects by individual developers. Some of those developers were then hired by MongoDB when their project became the primary entry-point for a programmer of that language. As a result, the drivers differ greatly between themselves.

There has been an initiative to define a “common architecture” that all drivers would adopt. From the user’s perspective, the common driver API would standardize the MongoDB developer experience for better clarity, documentation, and easy-of-use. However, it is not an easy task to establish a common design for all drivers because each language has its specific needs and idioms.