MongoDB and CFML

From the MongoDB website:

MongoDB (from "humongous") is a scalable, high-performance, open source, document-oriented database. MongoDB bridges the gap between key-value stores (which are fast and highly scalable) and traditional RDBMS systems (which provide rich queries and deep functionality).

MongoDB differs from traditional row-column based databases in that data is stored as documents with attributes. A document can have as many attributes as required, with not every document requiring the same amount of attributes. This makes it extremely efficient for applications that do not have a consistent data requirement.

In MongoDB, a document is "like" a row of data, except that it doesn't have to contain a constant set of attributes (columns) across all documents. A collection can be thought of like a database table, but unlike a traditional SQL server, you do not need to setup a collection up advance before using it. A document has a unique index identifier, _id. You do not need to worry about setting this (although you can if you wish).

The OpenBD CFML application engine has full integration with MongoDB, allowing CFML developers to quickly and easily utilise this powerful database without any fuss or hassle.

Setting up the Connection

Working with a MongoDB is not unlike working with Amazon SimpleDB. You register a MongoDB datasource with MongoRegister() function which accepts a name for the datasource, the remote server IP and port, plus any username/password that has been enabled.

<cfscript>
	MongoRegister( name="mongo", server="127.0.0.1", db="openbd" );
	var dbs = MongoDatabaseList( "mongo" );
	WriteDump( dbs );
</cfscript>

You can later, if you wish, call MongoDeRegister() function to remove the datasource from the server.

MongoDB is special compared to the likes of MySQL/SQLServer in that you do not have to set anything up prior to using it. So here, for example, we are referencing the database 'openbd' and if that does not exist, MongoDB server will create it there and then. This is true also of collections.

There are a number of operations you can perform on the database, like listing all the databases, dropping databases and you can send commands straight to the server for execution.

User Configuration Note
If you are running MongoDB as a remote server and experience problems connecting to databases with an admin user, you may have to create a standard user profile and assign relevant database privileges to that user. This is due to some restrictions MongoDB enforces when logging in admin users, where such a user can only initially be logged into the admin database before attempting a switch to other databases. MongoRegister does not currently support this switching between databases as it requires a static database with which to create the datasource. Therefore using a standard user profile, correctly configured with the relevant database privileges, is recommended.

You can find out more about user configuration for MongoDB over at MongoDB Security and Authentication.

Inserting Documents

Putting data into the database collection is extremely easy. Remember, MongoDB is a schema-less data storage. This means you do not need to setup the structure ahead of your data like you do with RDMS SQL databases. You store what you need, not what you hope to need.

Inserting a set of 100 documents in a collection can be as easy as the example below:

<cfloop index="x" from="1" to="100">

  <cfset MongoCollectionInsert( "mongo", "mycoll", {
     name:"Document" & x,
     age:x,
     children : {
       child1 : "name1",
       child2 : "name2",
       child3 : "name3"
     }
   })>

</cfloop>

As you can see, the natural syntax of CFML JSON makes formatting documents extremely easy. When a document is inserted, the MongoDB assigns it a unique _id identifier. This is an alphanumeric key that is assured to be unique and constant for that given document.

You can assign any type of attribute to a Document, including inner structures and arrays. The only limitation is that from MongoDB 1.9, a single document can not be greater than 16MB.

Updating Documents

There are a number of ways you can update a document in Mongo. If you are already working with a previously retrieved object, then you can save it using MongoCollectionSave().

<cfset MongoCollectionSave("mongo", "mycoll", mydoc, "NORMAL" )>

Alternatively you can update only subparts of the document using MongoCollectionUpdate().

The different with the upsert method is that if the record does not exist it will be created, otherwise the one that matches will be updated. Particularly handy for handling count situations.

Querying Documents

MongoDB comes with its own query language, which is very JSON like in how you describe how you wish to query the data. Full details can be found on the MongoDB website.

The example here, pulls back 10 results, starting at 0, whose age attribute is greater or equal to 40. Any documents that do not have the age attribute will not be returned.

<cfset results = MongoCollectionFind("mongo", "mycoll", {age: {"$gte":40} }, {}, 0, 10) >

The results object is an array of structures. In this case the full document is returned, but the second (and currently blank) structure argument can be used to define a subset of keys/fields to be returned, rather than the entire document. You can determine how many documents will match your query by first calling the MongoCollectionCount() method.

Mongo CFML Functions

You can see all the available functions here.

Further Reading

MongoDB is a very powerful server and while it takes a mental shift away from traditional SQL based servers, you will soon discover the power having a MongoDB server within your enterprise network will yield.