Addendum: The code examples below were built on earlier versions of MongoDB and will not work with 1.6+. Also, use Marc Esher's Github fork for the most current version of CFMongoDB.
From the perspective of a developer who prefers to think in terms of real-world objects, relational databases tend to slow me down. I'm not making some broad sweeping statement that "databases are bad" - they're not. They're just another layer of disparate technology that I need to contend with. What if we could just write code and store and retrieve those objects quickly? ORM and caching technologies do this well and they're aim is integration with relational databases, and Adobe has nicely integrated Hibernate into ColdFusion 9.
Alternatively, there's been some very interesting work done in the area of NoSQL, or schemaless data persistence. These efforts provide relatively small, fast, and distributed key-value data stores, and allow applications to store and retrieve objects in an efficient manner - and programmers don't have to worry about creating and managing tables or schemas. These projects include (among others) CouchDB, Tokyo Tyrant, and MongoDB. In short, these can be viewed as efficient and huMongous persistent hash tables. I chose to work with MongoDB simply because I found it the fastest to get up and running on both Unix and Windows.
Quick example usage (full CFML source available here):
<cfscript> blog = structNew(); blog.title = ''; blog.text = ''; blog.author = ''; </cfscript>
This is a very basic data structure (a CFML structure) representing a blog entity. We know what we would need to do to write this to a database - create the table(s), specify columns and datatypes, and write SQL to insert, update, delete, and fetch. Maybe we'll use stored procedures or DAOs, too. With MongoDB here's a simple example implementation - a proof of concept API:
<cfscript> mongo = createObject('component','MongoDB'); //create the blog blog = structNew(); blog.title = 'Look, Ma. No SQL! MongoDB and ColdFusion'; blog.text = 'Rapid development with MongoDB ...'; blog.author = 'bill shelton'; mongo.put(blog); </cfscript>
That's it - the entire structure is now persisted. For the jQuery and JavaScript folks, you're really going to like this. The stored data format (BSON - binary JSON) in string representation is plain old JSON and the MongoDB admin console is a JavaScript shell:
>db.default_collection.findOne() {"_id": ObjectId( "58c5b878f16bdb4a94f4d300") , "AUTHOR" : "bill shelton" , "TEXT" :"Rapid development with MongoDB ..." , "TITLE" : "Look, Ma. No SQL! MongoDB and ColdFusion"}How cool is that?
Adding additional fields or data. There's no need to create new tables or columns - MongoDB takes care of this for you. If they don't exist they'll be created. Just add the elements you need to your code. Let's add some tags and comments to our blog entity. Note that these are not simple string properties - this makes the example a bit more interesting and shows how powerful MongoDB can be.
<cfscript> mongo = createObject('component','MongoDB'); //create the blog blog = structNew(); blog.title = 'Look, Ma. No SQL! MongoDB and ColdFusion'; blog.text = 'Rapid development with MongoDB'; blog.author = 'bill shelton'; blog.tags = ['cool stuff', 'data persistence', 'hadoop']; blog.comments = [ comment = { author = 'anonymous', comment_text = 'you suck at unit testing' } ]; mongo.put(blog); </cfscript>
Here we added an array of tags and array of structs ... comments. Again, our entity is saved to the data store. Let's read this back out and print it:
<cfscript> mongo = createObject('component','MongoDB'); blog = mongo.findOne();// get the most recent entry writeoutout(blog.title); writeoutout(blog.author); writeoutout(blog.text); writeoutput(blog.comments[1].author); writeoutput(blog.comments[1].comments_text); </cfscript>
Here's a basic example of how to update and delete data.
<cfscript> blog = mongo.findOne();// get's the most recent blog.title = 'My New Blog Title'; mongo.update(blog); //if we want to delete it: mongo.delete(blog); </cfscript>
For someone who has embedded many lines of SQL in Java and CFML and knows the pain with keeping all the parts in synch, this is very appealing. Note the dot notation for traversing, too - It's familiar and fast. Also, my goal with all this as not to do a straight port of the Java driver. Rather, I tried for something extremely simple and fast for writing and fetching CFML structures to and from MongoDB datastores.
Though one of the big motivators for MongoDB seems to be geared towards creating very large distributed data stores, from a simple rapid development perspective, it's downright sexy.
Getting Started with MongoDB and ColdFusion
1. Download and start MongoDB - this is pretty much just downloading, unzipping, and running ./mongod. But, you might have to create a directory for the data. It's well documented and I was able to get it up and running in a couple of minutes on both Windows and Ubunutu.
2. Download the Java driver and put it in your ColdFusion server's classpath or use Mark Mandel's JavaLoader.
3. Check out the example code and the MongoDB wrapper for ColdFusion.
Note that there's a lot of other information about all this from both the developer's perspective and the admin perspective. I recommend reading up on use cases and schema design, as well as the other docs.
Next up: MongoDB query syntax .
Test and be Happy!
10 comments:
Hey Bill:
Very cool stuff. I'd heard of CouchDB before, but didn't quite grok what it was all about.
Looking forward to installing Mongo tonite and taking it for a spin.
Thanks, Charlie. Keep me posted on what you find, too. I plan at least 2 or 3 other posts on MongoDB, which I'm really liking. -bill
I'm glad some other people are exploring Object-Oriented Databases too! I've put some work into CouchDB for Coldfusion, but it still has a ways to go. It's nice that the MongoDB java driver works so well in CF!
I've been thinking it would really help promote OODBs for CF if there was a solid RIA Forge project using it. A blog seems like a good place to start...
Billy,
I am trying to play around with MongoDB, but I am running into a road block. The problem isn't with your CFC, but you seem to be very knowledgeable with ColdFusion and MongoDB so I thought I would ask you about it. I'm currently working locally on my Mac with CF8. The problem is when I instantiate the Mongo Class I get an UnsupportedClassVersionError exception. I've read where the java client requires JVM v1.5, which I have, but I don't know what sub-version the classes were complied on. I would think my options are to upgrade my JVM (which I am hesitant to do since things are working well right now) or to recompile the class files locally (but since I don't see the java files, I don't know if that is an option).
Am I missing something? Do you have any thoughts?
Thanks,
Evan Keller
Hi Evan, Which JVM version is your CF8 instance using? I ask because my Windows/CF8 uses 1.6.0_04 - I'll check my Ubuntu env later ... I suspect trying a different JVM would be a better path than recompiling the Java source to your VM. --bill
1.5.0_19
I am going to look into updating it. My Linux servers are running 1.6 so I was able to get it running over there.
Hi Bill,
Very nice article, and a good start point for using CF with MongoDB. However, when trying your example up and running, my CF9-local-dev-instance gave this error(see below). Or the BasicDBObject that is use to insert is wrong typed, or CF find somewhere a conflict with the insert name...
I'am using the mongo2.1.jar in the classpath of my CF (not the javaloader).
The insert method was not found.
Either there are no methods with the specified method name and argument types or the insert method is overloaded with argument types that ColdFusion cannot decipher reliably. ColdFusion found 0 methods that match the provided arguments. If this is a Java object and you verified that the method exists, use the javacast function to reduce ambiguity.
Greetings
Koen
Koen,
You're absolutely correct. This post was written using an older version of MongoDB. Version 1.6 is not compatible with the example code. I'll look up the change and note it here. You may also want to look at Marc Esher's work with CFMongoDB - http://github.com/marcesher/cfmongodb
bill
Hi Bill,
I'm trying your sample code given in this blog and am getting an error saying :
java.lang.IllegalArgumentException: can't serialize class com.mongodb.ObjectId
Here is my code:
config = createObject("component","cfmongodb.MongoConfig");
mongo = createobject("component","cfmongodb.Mongo").init(config);
db = mongo.query("neiltest");
person = {name="neil",age=27,job="developer"};
id = mongo.save(person,"neiltest");
person.job = "software developer";
mongo.update(person,"neiltest");
I cannot seem to update the person structure in the mongoDB. I'm using Marc Esher's version. Can you please help?
Regards,
Neil
Just posted a new project called CFMongoMap, this should make it easy for users to transform MongoDB objects -> CF Objects and vice versa...
This is a PRE BETA an I do need feedback on this.
http://cfmongomap.riaforge.org/
https://github.com/Hem/CFMongoMap/
Thanks
-Hem
Post a Comment