Mocking DBRefs in Mongoose and nodeunit

14 April 2011   0 comments   MongoDB, Javascript

Powered by Fusion×

Because this took me a long time to figure out I thought I'd share it with people in case other people get stuck on the same problem.

The problem is that Mongoose doesn't support DBRefs. A DBRef is just a little sub structure with a two keys: $ref and $id where $id is an ObjectId instance. Here's what it might look like on the mongodb shell:

> db.questions.findOne();
       "_id" : ObjectId("4d64322a6da68156b8000001"),
       "author" : {
               "$ref" : "users",
               "$id" : ObjectId("4d584fb86da681668b000000")
       "text" : "Foo?",
       "answer" : "Bar"
       "genre" : {
               "$ref" : "question_genres",
               "$id" : ObjectId("4d64322a6da68156b8000000")

DBRefs are very convenient because various wrappers on drivers can do automatic cross-fetching based on this. For example, with MongoKit I can do this:

for question in db.Question.find():

If we didn't have DBRefs you'd have to do this:

for question in db.Question.find():
   author = db.Authors.findOne({'_id':})
   print author.first_name

Anyway, the problem Mongoose has is that it doesn't support DBRefs so when you define its structure you have to do this:

var QuestionSchema = new mongoose.Schema({
  text     : String
  , answer      : String
  , genre: {},
  , author : {}
mongoose.model('Question', QuestionSchema);
var Question = mongoose.model('Question', 'questions');

Now, that sucks but I can learn to live with it. Giving this schema here's how you can work with the defined model from an existing database:

Question.find({}, function(err, docs) {
  docs.forEach(function(each) {
     each.findAuthor(function(err, item) {

(note: I have no idea with this "doc" struct is but perhaps the gods of Mongoose can explain that one)

So, given that I can't work with DBRefs in Mongoose; how do to mock it? Here's how:

    var author = new models.Author();
    author.username = "peter"; {
        var question = new models.Question();
        // fake a dbref = {
           "$ref" : "users",
           "oid" : user._id
        }; {
           question.findAuthor(function(err, u) {
              test.equal(u.doc.first_name, 'peter');

That's the magic. This way you can pretend, in your tests, that you have objects with proper DBRefs. It feels strangely convoluted and hackish but I'm sure once I've understood this better there might be a better way.

Perhaps I could have spent the time it took to figure this out and to write this blog I could have stepped up and written a DBRef plugin for Mongoose.


Your email will never ever be published

Related posts

Previous: - launched and ready! 06 April 2011
maxlength_countdown() - a useful jQuery plugin for showing characters left 01 May 2011
Related by keywords:
Fastest database for Tornado 09 October 2013
Speed test between django_mongokit and postgresql_psycopg2 09 March 2010
mongoengine vs. django-mongokit 24 May 2010
Mocking os.stat in Python 08 November 2009
How I made my MongoDB based web app 10 times faster 21 October 2010
Persistent caching with fire-and-forget updates 14 December 2011
Correction: running Django tests with MongoDB is NOT slow 30 May 2010
MongoUK 2011 - London conference all about MongoDB 21 March 2011
Optimization story involving something silly I call "dict+" 13 June 2011