themessup
themessup

Reputation: 192

MongoDB: can't return random document from collection

I'm working on a word game and am trying to return a random wordpair (my collection) on a page load. I'm using Express and have adapted my code from this tutorial if that's of any use.

A GET request renders my page just fine, and I'm trying to send a random WordPair object alongside the title:

router.get('/', function(req, res, next) {
  res.render('play', { title: 'play', random_wordpair: wordpair_controller.wordpair_random});
});

The wordpair_random function is here inside a controller file I've made (which also successfully manages listing the wordpairs and creating new ones etc).

// Get random WordPair
exports.wordpair_random = function() {
   WordPair.aggregate(
      [{
        $sample: {
          size: 1
        }
      }]
    )
    .exec(function(err, random_wordpair) {
      if (err) {
        return next(err);
      }
      console.log(random_wordpair);
      return random_wordpair;
    });
};

Then inside a play.pug template, I'm simply trying to display this result:

h3 random wordpair selection is: #{random_wordpair}

But all I can see is the function rendered as HTML text. Can anyone tell me what I'm doing wrong?

I also understand looking at the documentation for MongoDB $sample aggregation that I need to be calling my function on the database object, but I've seen various examples and some don't do this. When I try calling db.wordpair.aggregate(...) (or WordPair or wordpairs as it appears in mLab) directly after initializing db in my app.js file, I get undefined errors. My db object doesn't seem to contain the correct data for this request.

Thanks!

enter image description here

Upvotes: 0

Views: 121

Answers (1)

Lee
Lee

Reputation: 2992

I guess you're writing this in Node.JS. A core feature in Node.JS is non-blocking IO model. That means, the code won't wait for a database call to complete to move on.

Another concept you need to get it right is that Node.JS, being a variation of JavaScript, in nature is a functional programming. Assigning a function to a property of a JSON object like below won't cause the function to execute. It simply creates a pointer to the function body, that's why your application prints the function itself.

{ title: 'play', random_wordpair: wordpair_controller.wordpair_random}

To fix this, use a callback

exports.wordpair_random = function(callback) {
    WordPair.aggregate([$sample: {size: 1}}]).exec(callback);
};

Then in you web function:

router.get('/', function(req, res, next) {
    wordpair_controller.wordpair_random(function(err, result) {
        //Handle errors if needed. 
        res.render('play', { title: 'play', random_wordpair:result });
    })
});

Upvotes: 1

Related Questions