Searching for MongoDB object Ids in Li3

For the project I am currently working on we are using a MongoDB database and the PHP framework Lithium, Li3 for short. We chose Li3 because it works with MongoDB right out of the box so there is no additional plug-in setup. While I am fairly well versed in PHP, MongoDB is relatively new to me. I’ve slowly started to get the hang of it, but a i ran into an issue recently with Li3’s search method Model::find().

I had a two collections setup in my database, lets call them matches and match_reports, each document in these collections has an ObjectId as their Id field. The primary key of a MongoDB document is it’s _id field. Unless the _id field is provided a value at the time the document is created, MongoDB will assign an ObjectId to the field. ObjectIds are unique and quick to generate so they are a good option for unique Identifiers. In my matches_reports collection each document had a field called Match_id, the value in this field would be the corresponding Match’s Id field. So the Match_id field would be acting as a foreign key in the match_reports collection in this case, linking each match report to a match. Here is an example of a match_reports document:

db.find.match_reports({"_id" : ObjectId("55497d3002a6ce36393c0828")});
     {
	     "_id" : ObjectId("55497d3002a6ce36393c0828"),
	     "match_id" : ObjectId("55497d3002a6ce36393c0827"),
	     "Type" : "Hockey",
	     "Winner_Username" : Null
	     "Loser_Username" : Null
     }

I ran into a problem when I would try to search for a match report based on its match_id field. See doing a find on the _id field in Li3 is very simple, you just pass in the Id string(ie. “55497d3002a6ce36393c0828”) and Li3 will do the rest. Knowing this I assumed doing a find based on the match_id field would be fairly similar. Here is what my first attempt looked like:

$match_id = "55497d3002a6ce36393c0827";
$matchReport = MatchReports::find('first', array('conditions' => array('match_id' => $match_id)));

To my surprise this find did not return any documents. As it turns out with Li3 when search for ObjectIds the string Id will only work for the _id field. To search for mongo ObjectIds in other fields you will have to pass the find method a MongoId object instead of a string.

$match_id = new MongoId("55497d3002a6ce36393c0827");
$matchReport = MatchReports::find('first', array('conditions' => array('match_id' => $match_id)));

If you absolutely want to search based on the string of an ObjectId in a field other then the _id field you will have to save just the string when the document is created. You can do this using MongoId’s __toString() method.

Update 5/13/2015

I opened up an issue against Lithium’s github regarding this issue here. The li3 dev’s pointed out that if I setup a $_scheme for my match report model and identify the match_id field with the type id, calling finds based on match_id’s string value should work. So I setup my scheme and ran a few test and found it worked like a charm. Here is how I have my scheme setup:

protected $_scheme = array(
	 '_id' => array(
            'type' => 'id',
            'null' => false,
            'default' => null
        ),
        'match_id' => array(
            'type' => 'id',
            'null' => false,
            'default' => null
        ),
        'Type' => array(
            'type' => 'string',
            'null' => false,
            'default' => null
        ),
        'Winner_Username' => array(
            'type' => 'string',
            'null' => false,
            'default' => null
        ),
		'Loser_Username' => array(
			'type' => 'string',
			'null' => false,