1
votes

This is a bit trickier than one might first think. Or maybe I am just overthinking the problem.

Here is how I retrieve (two) random documents from MongoDB:

Character
  .find({ random: { $near: [Math.random(), 0] } })
  .where('voted', false)
  .limit(2)
  .exec(function(err, characters) {
    res.send({ characters: characters });
  }
});

What I would like to add is - finding by gender. Each document already has a gender field with value set to either female or male. What I need in other words: Give me two random documents that have a matching gender field.

Example: 2 random females, 2 random males, 2 random males, 2 random females, etc...

For more information on how to retrieve a random document from MongoDB: http://cookbook.mongodb.org/patterns/random-attribute/

1

1 Answers

1
votes

If your collection is large enough I think you can simply add random gender field to the query

var choices = {0: 'female', 1: 'male'}

.find({
    gender: choices[Math.round(Math.random())],
    random: { $near: [Math.random(), 0] }
})

but it won't solve the problem that your current results aren't really random. If you use limit(1) everything works like supposed, but when the limit is set to 2 things aren’t so simple. Let's say you have very simple collection like this:

> db.foo.find({}, {_id: 0}
{ "random" : [  1,  0 ] }
{ "random" : [  2,  0 ] }
{ "random" : [  3,  0 ] }
{ "random" : [  4,  0 ] }
{ "random" : [  5,  0 ] }

and perform query random: { $near: [Math.random() * 4 + 1, 0] } }) with limit(2). Every time the nearest document is { "random" : [ 3, 0 ] } as a second you'll get { "random" : [ 2, 0 ] } or { "random" : [ 4, 0 ] }.

Probably the best solution would to perform n separate queries and retrieving single random document each time.