Wednesday, October 29, 2014

Meteor and the findOne no result problem

Now that meteor has a version 1.0 release I wanted to give it another try.
As a test I was creating a simple blog.

The problem I encountered was when i tried to display a post detail. The code looked simple enough.

Router.route('/:_id', function(){
   this.render('detail', {
       data: function(){ 
           var templateData = { post: Posts.findOne({_id: this.params._id}) };
           return templateData;
       }    
   });
});

this.params._id looks almost like req.params._id from the express framework.
And I was sure the document with the _id existed because it came from the database.

During my search I found a few different ways to pass the _id to the findOne function.

The first one I tried comes from the official documentation:

Posts.findOne(this.params.id)

It looks like the mongo library that comes with meteor adds a little abstraction to the mongodb method. Great, but it didn't work.

Next there the id key without the underscore. That didn't work either.

Then i got the idea the hexstring wasn't enough. I needed the ObjectId instance like it's needed in the mongodb shell.
Of course the mongo ObjectId isn't available in Meteor.

After a bit of searching i found that the meteor Mongo library has a ObjectID method.

Router.route('/:_id', function(){
   this.render('detail', {
       data: function(){ 
           var postId = new Mongo.ObjectID(this.params._id); 
           var templateData = { post: Posts.findOne({_id:postId}) };
           return templateData;
       }    
   });
});

And the document data was visible.

Update

It looks like the meteor mongo shell produces _ids that are ObjectId objects, but inserting documents with the meteor Mongo library produces _ids that are 'plain' hexstrings.

So to insert documents you best use the meteor Mongo library because that's the way you interact with mongo the most.