1

I run an IRC bot and I have a function which returns 1 random url using Math.random at the moment, from my Mongodb collection.

I would like to refactor it to return x number of unique items, and for each subsequent invocation of the url fetching command .getlinks I would like that it keeps everything unique, so that a user doesn't see the same link unless all the possible links have been already returned.

Is there some algorithm or native mongodb function I could use for this?

Here's a sample scenario:

I have a total of 9 records in the collection. They have a _id and url field.

user a: .getlinks()
bot returns: http://unique-link-1, http://unique-link-2, http://unique-link-3, http://unique-link-4

user a: .getlinks()
bot returns: http://unique-link-5, http://unique-link-6, http://unique-link-7, http://unique-link-8

user a: .getlinks()
bot returns: http://unique-link-9, http://unique-link-6, http://unique-link-1, http://unique-link-3

Background information:

  • There's a total of about 200 links. I estimate that will grow to around 5000 links by the end of next year.

Currently the only thing I can think of is keeping an array of all returned items, and grabbing all items from the collection at once and getting a random one 4 times and making sure it's unique and hasn't been shown already.

var shown = [], amountToReturn = 4;
function getLinks() {
   var items = links.find(), returned = [];
   for ( var i = 0; i<amountToReturn; i++ ) {
      var rand = randItem( items );
      if ( shown.indexOf( rand.url ) == -1 && shown.length < items.length ) ) {
         returned.push( rand.url );
      }
   }
   message.say( returned.join(',') );
}
meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • This question has been asked in many forms here on Stack Overflow. The most popular question is [Random record from MongoDB](http://stackoverflow.com/questions/2824157/random-record-from-mongodb) -- it has good responses. That said, I think the best way of thinking about the question is not to think about getting one random document but, rather, randomizing a result set. See [Ordering a result set randomly in Mongo](http://stackoverflow.com/questions/8500266/ordering-a-result-set-randomly-in-mongo) for that. – David J. Jun 17 '12 at 02:42

2 Answers2

2

You should find a number of possible options to get random item(s) from Collection here ...

http://jira.mongodb.org/browse/SERVER-533

Another intersting method is documented here ...

http://cookbook.mongodb.org/patterns/random-attribute/

The method mentioned above basically creates a new key/value on the document using Math.random()

> db.docs.drop()
> db.docs.save( { key : 1, ..., random : Math.random() } )
> db.docs.save( { key : 1, ..., random : Math.random() } )
> db.docs.save( { key : 2, ..., random : Math.random() } )
... many more insertions with 'key : 2' ...
> db.docs.save( { key : 2, ..., random : Math.random() } )
...
Justin Jenkins
  • 26,590
  • 6
  • 68
  • 1,285
1

Get random records form mongodb via map/reduce

// map
function() { 
    emit(0, {k: this, v: Math.random()}) 
}

// reduce
function(k, v) {
  var a = []
  v.forEach(function(x) {
    a = a.concat(x.a ? x.a : x)
  })
  return {a:a.sort(function(a, b) {
    return a.v - b.v;
  }).slice(0, 3 /*how many records you want*/)}; 
}

// finalize
function(k, v) {
  return v.a.map(function(x) {
    return x.k
  })
}
iron9light
  • 1,205
  • 1
  • 13
  • 17