Lucee MongoDB Extension

Update: Looks like this is a bug in the MongoDB extension. A ticket has been raised to fix the compatibility issue, so look for an update soon. Meanwhile, if you need your aggregate function working on Lucee, look to the kind of fix described below.

With the release of Lucee, Micha Offner announced on the Lucee Google Group the availability of the MongoBD extension released as an open source project on BitBucket under LGPL 2.1 I installed the extension to Lucee and immediately came across a difference in my existing code that has required some updating. Specifically, using the $aggregate operator in Mongo led me to some syntax that would not be normal in the mongo shell. This code:

local.result = deserializeJSON( mongoDb['fs.files'].aggregate({ "$match": { "metadata.personId" : arguments.personId, "metadata.disabled": 1 }},
                    [    { "$group": { "_id": "null", "count": { "$sum": 1 } } }
                    ])
                );

if( arrayIsEmpty( local.result.result ) ){
    return 0;
}else{
    return local.result.result[1].count;
}

 

returns the count of deleted ("metadata.disabled" : 1) documents for a user. This is how the code worked in Railo, but now this code complains in Lucee. After some checking with proper syntax in the mongo shell, I found this code to fix the problem:

 

local.result =  mongoDb['fs.files'].aggregate(
         { "$match": { "metadata.personId" : arguments.personId, "metadata.disabled": 0 }},
         { "$group": { "_id": "null", "count": { "$sum": 1 } } }
     );
local.result = local.result.results();

if( arrayIsEmpty( local.result ) ){
     return 0;
}else{
     return local.result[1]['count'];
}

 

To find out what's going on in the code, let's do a little debugging. Running the second mongo aggregate function to return a value from MongoDB and dumping the initial local.result variable, we get this:

 

AggregationOutputImpl

class

org.lucee.mongodb.AggregationOutputImpl

methods

return

interface

exceptions

java.lang.String

toString()

 

java.lang.Iterable

results()

 

java.lang.Object

getCommandResult()

 

com.mongodb.ServerAddress

getServerUsed()

 

com.mongodb.AggregationOutput

getAggregationOutput()

 

java.lang.Object

getCommand()

 

java.util.Collection

values(lucee.runtime.type.Collection)

 

java.lang.Object

clone()

 

java.util.Set

entrySet(lucee.runtime.type.Collection)

 

void

putAll(lucee.runtime.type.Collection, java.util.Map)

 

java.lang.Object

toCFML(java.lang.Object)

 

int

checkArgLength(java.lang.String, java.lang.Object[], int, int)

lucee.runtime.exp.PageException

com.mongodb.DBObject

toDBObject(lucee.runtime.type.Struct)

 

com.mongodb.DBObject

toDBObject(java.lang.Object)

lucee.runtime.exp.PageException

com.mongodb.DBObject

toDBObject(java.lang.Object, com.mongodb.DBObject)

 

java.lang.Object[]

toNativeMongoArray(java.lang.Object)

 

com.mongodb.WriteConcern

toWriteConcern(java.lang.Object, com.mongodb.WriteConcern)

 

lucee.runtime.dump.DumpData

__toDumpData(java.lang.Object, lucee.runtime.PageContext, int, lucee.runtime.dump.DumpProperties)

 

com.mongodb.DBObject[]

toDBObjectArray(java.lang.Object)

lucee.runtime.exp.PageException

java.util.Map

toMongo(java.util.Map)

 

java.lang.Object

toMongo(java.lang.Object)

 

 

Methods inherited from java.lang.Object

wait, wait, wait, equals, hashCode, getClass, notify, notifyAll

 

So the first thing I see is that the result is returning a Lucee Java class, org.lucee.mongodb.AggregationOutputImpl. Looking at the method list, I see the results() method that returns a java.lang.Iterable. Running again an dumping local.result.results() gives the result value that was previously being delivered in Railo.

I have not looked at the differences in the code, but the results of the new extension are clearly more in line with the syntax that would be used in the Mongo shell.