-
Notifications
You must be signed in to change notification settings - Fork 40
CFMongoDB Object Mapper Syntax (proposed)
This is proposed syntax and subject to change. Unstable code can be found in the 0.9 branch.
Much of this has not been implemented and any suggestions are appreciated
There could be 4 ways to create persistent objects in a MongoDB datastore using the CFMongoDB Object Mapper :
(1) Extending cfmongodb.components.MongoDocument,
(2) Using the mongo.new_doc() factory method,
(3) Working directly with ColdFusion structures
(4) Creating a decoupled Object in CF and passing that to a Mongo method. NEW IDEA!
This provides 2 different approaches to generating the same types of objects. There are other ways, too [to do].
This is similar to CF9’s ORM syntax where you specify the fields you intend to persist as cfproperty
tags. Though not required, this articulates what you intend to persist and initializes the model/data with default values (if any). The MongoDocument class has methods for storing and manipulating objects in the Mongo datastore – save(), update(), etc. [to do – link to API].
<cfcomponent displayName="MyBlog" extends="cfmongodb.components.MongoDocument">
<cfproperty name="title" />
<cfproperty name="author" />
<cfproperty name="pub_date" />
<cfproperty name="body" />
<cfproperty name="comments" type="array" />
<cfset super.init( collection_name='blog' ) />
<cffunction name="validate">
<!--- Insert custom code which will be executed prior to saves and updates --->
</cffunction>
</cfcomponent>
To create a new MyBlog object and store it in Mongo, create the following client code:
<cfscript>
my_blog = createObject( "component", "MyBlog" );
my_blog.set( 'title', 'My New Blog Title' );
my_blog.set( 'author', 'bill' );
my_blog.set( 'pub_date', now() );
my_blog.set( 'body', 'My brilliant ideas ...' );
my_blog.save();
</cfscript>
<cfscript>
mongo= createObject( 'component', 'cfmongodb.components.MongoDb' );
my_blog = mongo.new_doc( collection_name='blog' );
my_blog.set( 'title', 'My New Blog Title' );
my_blog.set( 'author', 'bill' );
my_blog.set( 'pub_date', now() );
my_blog.set( 'body', 'My brilliant ideas ...' );
my_blog.save();
</cfscript>
The primary difference between the two methods is the way in which documents are created. But both methods perform identical tasks.
At a lower level, MongoDB persists data as JSON (technical BSON) and the Java Driver accepts a Hashmap as the data. For ColdFusion, this gives us tremendous flexibility by allowing to pass in structs as the data we would want to persist.
Note that the intent of this approach (which is the most appealing) is to totally decouple the Object from the persistence mechanism. This could potentially provide flexibility for applications that wish to use the built-in CF9 ORM or some other persistence mechanism, but use the same syntax, which is to define object properties and specify whether or not they are persistent:
//define the cf object: <cfcomponentn displayName="MyObject"> <cfproperty name="name" type="string" persistent="true" /> <cfproperty name="email" type="string" persistent="true" /> ...other object specific logic </cfcomponent> .... //persistence mechanisim (decoupled/separate object) my_obj = createObject("component", "myapp.MyObject"); mongo = createObject("component", "cfmongodb.Mongo").init( {props} ); my_obj.setName('bill'); my_obj.setEmail('[email protected]'); id = mongo.save(my_obj); // fetch ... my_clone = mongo.fetch( id ); assert ( my_obj.getName() == my_clone.getName() );
1. Create a instance of a MongoDocument
2. Retrieve an existing object using a known unique value; e.g. ObjectId ( _id )
3. Set the value of existing properties (or add new ones)
4. Call the update() method
In-place updates are not yet implemented, but are at the top of the list :-)
<cfscript>
my_blog = createObject( 'component', 'cfmongodb.components.MongoDocument');
my_blog = my_blog.fetch( '0x670Ac452B' );
my_blog.set( 'body' , 'An even better idea ...');
my_blog.update();
</cfscript>
Future versions will include in-place updates and should look something like:
<cfscript>
my_blog = createObject( 'component', 'cfmongodb.components.MongoDocument');
my_blog = my_blog.fetch( '0x670Ac452B' );
my_blog.update( 'body', 'An even faster update!');
</cfscript>
Similar to updating, once a reference to a document object is retrieved, call the delete()
method on the MongoDocument class:
<cfscript>
my_blog = createObject( 'component', 'cfmongodb.components.MongoDocument');
my_blog = my_blog.fetch( '0x670Ac452B' );
my_blog.delete();
</cfscript>
mongoDB supports storing BLOBS. It’s accomplished via the GridFS (Grid File System). Ideally, the API would hide the details of how this is implemented from developers, yet it will be available if needed. I’m not sure of the feasibility, yet, unlike all the other features.
<cfscript>
avatar = fileRead( '/tmp/some_pic.png' ); //or via file upload ... any byte array, really
mongo= createObject( 'component', 'cfmongodb.components.MongoDb' );
my_blog = mongo.new_doc( collection_name='blog' );
my_blog.set( 'title', 'My New Blog Title' );
...
my_blog.set( 'avatar', avatar);
my_blog.save();
//display the image:
???
</cfscript>
DBRefs can be used to store references to objects that exist in another collection. This is similar to a foreign key reference in relational terms.
Once a MongoDocument has been retrieved, call the dbref() method to generate a DBRef object. This object can then be stored as a property in another document:
<cfscript>
mongo= createObject( 'component', 'cfmongodb.components.MongoDb' );
my_blog = mongo.new_doc( collection_name='blog' );
my_blog.set( 'title', 'My New Blog Title' );
...
my_blog.save();
blog_ref = my_blog.dbref();
my_site = mongo.new_doc( collection_name='sites' );
my_site.set( 'blog', blog_ref );
my_site.save();
</cfscript>
The original object should be returned when performing a get()
:
<cfscript>
blog = my_site.get( 'blog' );
assertIsTypeOf( blog, 'cfmongodb.components.MongoDocument' );
writeoutput( blog.get( 'title' );
...
</cfscript>