Giter VIP home page Giter VIP logo

cfmongodb's Introduction

CFMongoDB

CFMongoDB is both partial wrapper for the MongoDB Java driver and a document-struct mapper for ColdFusion. It attempts to remove the need for constant javacasting in your CFML when working with MongoDB. Additionally, there’s a simple DSL which provides ColdFusion developers the ability to easily search MongoDB document collections.

CFMongoDB works with Adobe ColdFusion 9.0.1+ and Railo 3.2+

Notes

As of August 20, 2011, collection.update(), collection.findAndModify(), and “sort” all introduced breaking changes!

update() and findAndModify()

They no longer wrap documents in {$set} automatically.

You will need to change your “update” documents like so:

old: {newField="hey"}

new: { “$set” = {newField="hey"} }

sort

Sort must now be a structure… string support is no longer supported.

old: find(sort=“TS=-1”)

new: find(sort={"TS"=-1})

Some Code

One of the most appealing aspects is that data can be created as a ColdFusion structure and persisted almost verbatim. Example:

<cfscript>

//save
col = mongo.getDBCollection( 'my_collection' );
my_struct = {
  name = 'Orc #getTickCount()#'
  foo = 'bar'
  bar = 123
  'tags'=[ 'cool', 'distributed', 'fast' ]
};

col.save( my_struct );

//query
result = col.query().startsWith('name','Orc').find(limit=20);
writeOutput("Found #result.size()# of #result.totalCount()# Orcs");

//use the native mongo cursor. it is case sensitive!
cursor = result.asCursor();
while( cursor.hasNext() ){
  thisOrc = cursor.next();
  writeOutput(" name = #thisOrc['name']# <br>");
}

//use a ColdFusion array of structs. this is not case sensitive
orcs = result.asArray();
for(orc in orcs){
  writeOutput(" name = #orc.name# <br>");
}

</cfscript>

More Examples

See examples/gettingstarted.cfm to start.

Additional examples are in the various subdirectories in examples/

The Wiki

Check out the wiki for additional info: http://wiki.github.com/marcesher/cfmongodb/

Getting Help

We have a Google group: http://groups.google.com/group/cfmongodb

Please limit conversations to MongoDB and ColdFusion. General MongoDB questions are best asked on the MongoDB group at http://groups.google.com/group/mongodb-user

Posting Issues

Post issues to the github issue tracker for the project. Better: post fixes. Best: post fixes with unit tests.

Getting Involved

Collaboration is welcome. Fork — Commit — Request a pull. For bug fixes and feature additions, commits with unit tests are much more likely to be accepted.

Code well.

cfmongodb's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cfmongodb's Issues

More unit tests for update

"update" is a beast which behaves differently based on values of certain params, namely "multi" and "upsert".

We need thorough unit tests around those conditions

Support Aggregation Framework

Add support for the aggregation framework added in Mongo 2.1. This will require updating the Java driver to 2.9.0.

I have begun work on this in a new branch in my fork, please let me know if you have any plans or in progress work already, I wouldn't want to duplicate efforts. I'll send a pull request when I have it working. Not sure if you want to start a feature branch for this or just pull my changes directly into development. Let me know what you think.

Handling of a bad mapReduce

This is most likely a simple bug on my part, but cfmongo db isn't handling the error right. I'm trying to mapReduce a complex set of data down to report on tags. Given that I'm probably doing it wrong, this is the error I get:

Element result is undefined in a Java object of type class com.mongodb.CommandResult.

The error occurred in C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\cfmongodb\core\DBCollection.cfc: line 255
253 : var commandResult = mongoDB.command( dbCommand );
254 :
255 : var mrCollection = mongo.getDBCollection( commandResult["result"] );
256 : var searchResult = mrCollection.query().find();
257 : var mapReduceResult = createObject("component", "MapReduceResult").init(dbCommand, commandResult, searchResult, mongoUtil);

Looks like result may not always exist in commandResult. A simple structKeyExists would help that (or an isnull check if the key exists and the value is null).

cfmongodb.lib.javaloader.JavaLoader Case-sensitivity

Hey Marc,

Great job! Loving it so far. <-- that's not the bug ;)

In JavaloaderFactory.cfc, when it calls cfmongodb.lib.javaloader.javaloader, on CentOS 5.4 64-bit, I was getting an error that it couldn't be found.

So, I fixed the case to match the file name (cfmongodb.lib.javaloader.JavaLoader), and it worked. Strange thing is that it worked on my local CentOS 5.4 VM, but not on live, and a best I can tell they're exactly the same. But it's probably over my head, and the point is that when the case matched, it worked great, and so I imagine it's an easy fix :)

Peace bro

Inline mapReduce() currently not possible.

If you just want to do an inline mapReduce() the current version of the DBCollection.cfc will run into a whole cascade of problems.

Example: mongodb.getDBCollection(LOCAL.collectionName).mapReduce( map=LOCAL.map, reduce=LOCAL.reduce, query=LOCAL.query, outputType="inline" );

  1. The line var out = {"#lcase(outputType)#" = outputTarget}; will result in The key [OUTPUTTARGET] does not exist
  2. Fixing that by assigning an empty string as a default of the outputTarget then leads to a Key [result] doesn't exist in Map (com.mongodb.CommandResult) in the var mrCollection = mongo.getDBCollection( commandResult["result"] );line further down.
  3. A quick dump of the commandResultobject shows that there's a results key instead, which contains the data I want, but since since the line var mrCollection = mongo.getDBCollection( commandResult["results"] ); expects the name of a collection to read from there even though it's not really necessary, we're facing another problem.

In my case it's probably enough to just return the "results" key in case of inline uses, but it would be great if someone with more experience could take a look at this problem.

Thanks in advance!

BTW: Current workaround is to just use the command(createOrderedDBObject( foo )) approach.

Refactor Mongo.cfc and return to a Collection

With the recent spate of feature additions, it's obvious that Mongo.cfc's taking on way too much responsibility.

We need to revert to how we started, with breaking out Collection-related behavior in a Collection.cfc. To retain backward compatibility we can still provide delegating functions into Mongo.cfc, perhaps either directly or through onMissingMethod.

Once complete all unit tests and example pages should be refactored to use the collection functions if we deem that appropriate.

Issues with MongoDB 2.6 and CFMongoDB

It appears the find method is no longer returning records that match the criteria specified using MongoDB 2.6.x (did not work with 2.6.1 or 2.6.3)). A find is returning 0 results, regardless of the criteria, unless I put a limit. Limit is functioning, but it ignores any search criteria specified. The asArray() method is extremely slow and mostly returns error 500. Is anyone else seeing these problems?

Geo queries fails with maxDistance

Geoqueries like $near and $nearSphere often fails if $maxDistance is specified, returning the following error:

-- geo values have to be numbers: { $maxDistance: 0.00391972405142678, $nearSphere: [ 45.46427, 9.18951 ] }

this geo query is order sentisive and maxDistance should not precede nearSphere

the following query returns the correct results
'Position' : { $nearSphere: [ 45.46427, 9.18951 ] ,$maxDistance: 0.00391972405142678}

problems importing to mongo from a query

so, i've recently switched from the railo mongodb extension to cfmongodb because i'm having problems with my data landing in a proper mongodb format. I'm working on a routine which will perform a CFQUERY against a VisualFoxPro ODBC connection(barf), then stash the records in mongodb. the mongodb data will later be consumed by a nodeJS app. two problems i'm having

  1. i was setting _id to a particular field in my db, for example, the old db has a "drivernumber" field, so i was feeding that into _id because on the nodeJS side, i'm using mongoose ODM to handle "joining" the data when needed. This field is essentially a string. it works in both the mongodb extension for railo and mongodb itself, but throws an error "invalid objectID".. Is that something i can work around with some modification?

  2. this is the big one for me. I'm taking the cfquery results, iterating, converting to a struct (queryRowToStruct) and then stashing that in mongodb. I'm still getting string for everything. I've tried various javaCast and createObject(...javaDate..).init(mydate).. but its still landing as a string! further investigation indicates similar behavior is happening to ints as well.. Is it the fact that i'm converting to a struct? Also, can i feed a full query into some method in your wrapper?

any help would be great! i'm on the vere of just using epoch time, but i don't think that'll work quite right given the fact that it'd still be a string, mongo might not order it correctly..

requiredReplicaSetName not supported as a MongoClientOption

It seems that 'requiredReplicaSetName' is not supported in the 'com.mongodb.MongoClientOptions$Builder'. It was introduced in 2.12

Do I need to rebuild the cfmongodb.jar to acknowledge the client option?

If I load the latest mongodb jar file 2.13 etc. I can see the option in the builder.

Upgrade to 2.6.5 Java driver

There have been a lot of robustness fixes in the driver since 2.6.2 so you'd benefit from that. I upgraded CongoMongo, the Clojure wrapper, to 2.6.5 recently and we have that in production.

ns doesn't exist

I don't know what's going on here - but previously working code is now giving me this error:

Error Message: ns doesn't exist:

The error occurred in C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\cfmongodb\core\DBCollection.cfc: line 253
251 :
252 : if( NOT commandResult['ok'] ){
253 : throw("Error Message: #commandResult['errmsg']#:", "MapReduceException", '', '', serializeJson(commandResult));
254 : }
255 :

Stack trace:
Resources:
Check the ColdFusion documentation to verify that you are using the correct syntax.
Search the Knowledge Base to find a solution to your problem.
Browser Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.218 Safari/535.1
Remote Address 127.0.0.1
Referrer
Date/Time 02-Sep-11 09:59 AM
Stack Trace
at cfDBCollection2ecfc568624714$funcMAPREDUCE.runFunction(C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\cfmongodb\core\DBCollection.cfc:253) at cftopicreport2ecfm222070932.runPage(C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\topicreport.cfm:31)

coldfusion.runtime.CustomException: Error Message: ns doesn't exist:
at coldfusion.tagext.lang.ThrowTag.doStartTag(ThrowTag.java:142)
at coldfusion.runtime.CfJspPage._emptyTcfTag(CfJspPage.java:2722)
at cfDBCollection2ecfc568624714$funcMAPREDUCE.runFunction(C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\cfmongodb\core\DBCollection.cfc:253)
at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:517)
at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:496)
at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:355)
at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2301)
at cftopicreport2ecfm222070932.runPage(C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\topicreport.cfm:31)
at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:231)
at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:416)
at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65)
at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:360)
at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)
at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
at coldfusion.filter.PathFilter.invoke(PathFilter.java:94)
at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
at coldfusion.CfmServlet.service(CfmServlet.java:200)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at jrun.servlet.FilterChain.service(FilterChain.java:101)
at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
at jrunx.scheduler.ThreadPool$DownstreamMetrics.invokeRunnable(ThreadPool.java:320)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
at jrunx.scheduler.ThreadPool$UpstreamMetrics.invokeRunnable(ThreadPool.java:266)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)

$inc not working

Downloaded, installed, configured CFMongoDB into my prototype
application and all the examples work in /examples/gettingstarted.cfm
EXCEPT for the $inc example:

    //perform an $inc update???? Doesn't work?? 
    cast = [{NAME = "Wesley", LIFELEFT=50, TORTUREMACHINE=true}, 
            {NAME = "Spaniard", LIFELEFT=42, TORTUREMACHINE=false}, 
            {NAME = "Giant", LIFELEFT=6, TORTUREMACHINE=false}, 
            {NAME = "Poor Forest Walker", LIFELEFT=60, TORTUREMACHINE=true}]; 
    people.saveAll( cast ); 
    suckLifeOut = {"$inc" = {LIFELEFT = -1}}; 
    victims = {TORTUREMACHINE = true}; 
    people.update( doc = suckLifeOut, query = victims, multi = true ); 
    rugenVictims = people.query().$eq("TORTUREMACHINE", 

true).find().asArray();
writeOutput("

Atomically incrementing with $inc

");
writeDump( var = cast, label="Before the movie started",
expand=false);
writeDump( var = rugenVictims, label="Instead of sucking water, I'm
sucking life", expand=false);

When I ran it, the writeDump output for the result didn't show the
LIFELEFT value decreasing by 1. It actually shows the data {"$inc" =
{LIFELEFT = -1} being added as a new property into the targeted
documents. I also verified by querying MongoDB directly as so and got the
following result:

db.people.find({"TORTUREMACHINE":true})

{ "$inc" : { "LIFELEFT" : -1 }, "LIFELEFT" : 50, "NAME" : "Wesley",
"TORTUREMACHINE" : true, "_id" :
ObjectId("4e47048b5ba833d562a1f8d9") }
{ "$inc" : { "LIFELEFT" : -1 }, "LIFELEFT" : 60, "NAME" : "Poor Forest
Walker", "TORTUREMACHINE" : true, "_id" :
ObjectId("4e47048b5ba833d562a1f8dc") }

Add Geo support in SearchBuilder.cfc

Mongo Supports lightweight geospatial searching, described here: http://www.mongodb.org/display/DOCS/Geospatial+Indexing

I've added an ensureGeoIndex function into Mongo.cfc for creating the indexes, and you can currently use cfmongodb. to perform geo queries like so:

nearResult = mongo.query( collection ).add( "LOC", {"$near" = [38,-85]} ).search(limit=10);

But this is not idiomatic CFMongoDB and I'd like to add functions in SearchBuilder for building up the handful of geo queries.

I'm thinking something like:

mongo.query(coll).$near(field, min, max);

mongo.query(coll).$near(field, min, max, maxDistance);

we'd want support for $within, both "box" and "center", which would probably translate into

withinBox(..) and withinCenter(...)

Anything else?

Case inSensitivity in SearchBuilder like() and regex()

I'm working on a pull request adding the ability to do case insensitive queries in SearchBuilder. I'd like your opinion. I'm basically planning on adding regexnocase() for this, and I could also add likenocase(), but my preference would be to make like() itself case-insensitive.

What do you think?

abnormal behavior with find operation

Hi Marc,

Jack (my colleague) and I found something that I can't explain. In a collection, the find operation will behave differently when there's 1 and more than 1 documents. I tested it on 2 machines with CF9 and CF10, both had same abnormal result. Jack ran the same test with pure Java driver, it behaves normally.

Here's how to test it:

empty a collection and insert documents in test case 1, run test code. Do the same operation with test case 2. Both test cases should output the same result. But it did not.

test case 1:
{ "id1" : "3", "id2" : 4 }

test case 2:
{ "id1" : "3", "id2" : 4 }
{ "id1" : 10, "id2" : "11" }

test code:

writeOutput("finding 3: ");
if (coll.query().$eq("id1", 3).find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/>");

writeOutput('finding "3": ');
if (coll.query().$eq("id1", "3").find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/>");

writeOutput('finding javaCast("int", 3): ');
if (coll.query().$eq("id1", javaCast("int", 3)).find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/>");

writeOutput('finding javaCast("string", "3"): ');
if (coll.query().$eq("id1", javaCast("string", "3")).find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/><hr/>");

writeOutput("finding 4: ");
if (coll.query().$eq("id2", 4).find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/>");

writeOutput('finding "4": ');
if (coll.query().$eq("id2", "4").find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/>");

writeOutput('finding javaCast("int", 4): ');
if (coll.query().$eq("id2", javaCast("int", 4)).find().asCursor().size() == 1) writeOutput("found");
writeOutput("<br/>");

writeOutput('finding javaCast("string", "4"): ');
if (coll.query().$eq("id2", javaCast("string", "4")).find().asCursor().size() == 1) writeOutput("found");

Integrate new MongoClient

With 2.2 the API has changed and now MongoClient is the preferred entry point.

When integrating, ensure that the mistakes we made with Mongo are addressed. Specifically, ensure that all options passable to the Java API are available in the cfmongodb API as well.

http://api.mongodb.org/java/2.10.1/

Proposed Change to Mongo.getDBCollection() To Support Using Multiple Databases

I am working on an application that uses several separate Mongo databases. I would like to be able interact with all of these databases using a single Mongo connection in my application. I'm currently doing this by using the underlying java objects:

getMongoDB().getSisterDB("myotherdb").getCollection("collectionName")

But of course this means I need to interact with collections from the sister DBs differently than I do the main connection DB. I would like to be able to use the cfmongodb DBCollection object for these as well.

What I was thinking was to add an optional second argument dbName to Mongo.getDBCollection() which would return a DBCollection object pointing to the sister database collection:

Mongo.getDBCollection("collectionName","dbName");

Does this seem like a reasonable approach? Is there something I'm missing that would allow me to do this already?

Need to provide for a MongoOptions object set into MongoConfig, passed to Mongo on init

We need to provide for a MongoOptions object that is passed into mongo on init. This is necessary for replica sets with read-only members because the cheap-ass "getIndexes" read for authentication checking will fail on those read-only slaves unless slaveOK is set to true, and currently there's no way to set it to true.

It'd nice to have for overriding maxWaitTime to have it fail faster when it can't connect

Finish aggregate()

  1. get rid of mongodb.command() and use the DBCollection.aggregate() method
  2. return a proper result object which essentially mimics the AggregationOutput object
  3. tests... must cover single pipeline operation, multiple pipeline operations, failures
  4. update aggregation/aggregate.cfm

split datatyping into separate functions... one for collection documents, and one for operational documents such as sort, exclude, etc

need to separate the datatype classes into a full-blown one that is applied to all Adobe CF documents, which is the current behavior, and a separate IntegerOnlyTyper which is applied to all 'operational' documents such as sort, excludefields, etc.

this way, we can safely and consistently apply the IntegerOnlyTyper to operational behavior, and then on Railo continue to use the "NoTypeTyper" since Railo generally gets types correct.

Handling of Mongo being down

If you run code and Mongo itself is down, the error isn't incredibly clear:

The system has attempted to use an undefined value, which usually indicates a programming error, either in your code or some system code.
Null Pointers are another name for undefined values.

The error occurred in C:\Users\Raymond\Dropbox\websites\testingzone\deepcomment\cfmongodb\core\DBCollection.cfc: line 365
363 : }
364 : var dbo = toMongo(doc);
365 : var writeResult = collection.remove( dbo );
366 : return writeResult;
367 : }

It seems like Mongo could handle this a bit better?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.