Created
November 19, 2014 21:04
-
-
Save mirek/123840fc3a8e5c7a68d9 to your computer and use it in GitHub Desktop.
Find random document in MongoDB collection.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Install packages: | |
// npm install mongodb async | |
// Add index in mongo: | |
// db.ensureIndex('mycollection', { rand: 1 }) | |
var mongodb = require('mongodb') | |
var async = require('async') | |
// Find n random documents by using "rand" field. | |
function findAndRefreshRand (collection, n, fields, done) { | |
var result = [] | |
var rand = Math.random() | |
// Append documents to the result based on criteria and options, if options.limit is 0 skip the call. | |
var appender = function (criteria, options, done) { | |
return function (done) { | |
if (options.limit > 0) { | |
collection.find(criteria, fields, options).toArray( | |
function (err, docs) { | |
if (!err && Array.isArray(docs)) { | |
Array.prototype.push.apply(result, docs) | |
} | |
done(err) | |
} | |
) | |
} else { | |
async.nextTick(done) | |
} | |
} | |
} | |
async.series([ | |
// Fetch docs with unitialized .rand. | |
// NOTE: You can comment out this step if all docs have initialized .rand = Math.random() | |
appender({ rand: { $exists: false } }, { limit: n - result.length }), | |
// Fetch on one side of random number. | |
appender({ rand: { $gte: rand } }, { sort: { rand: 1 }, limit: n - result.length }), | |
// Continue fetch on the other side. | |
appender({ rand: { $lt: rand } }, { sort: { rand: -1 }, limit: n - result.length }), | |
// Refresh fetched docs, if any. | |
function (done) { | |
if (result.length > 0) { | |
var batch = collection.initializeUnorderedBulkOp({ w: 0 }) | |
for (var i = 0; i < result.length; ++i) { | |
batch.find({ _id: result[i]._id }).updateOne({ rand: Math.random() }) | |
} | |
batch.execute(done) | |
} else { | |
async.nextTick(done) | |
} | |
} | |
], function (err) { | |
done(err, result) | |
}) | |
} | |
// Example usage | |
mongodb.MongoClient.connect('mongodb://localhost:27017/core-development', function (err, db) { | |
if (!err) { | |
findAndRefreshRand(db.collection('profiles'), 1024, { _id: true, rand: true }, function (err, result) { | |
if (!err) { | |
console.log(result) | |
} else { | |
console.error(err) | |
} | |
db.close() | |
}) | |
} else { | |
console.error(err) | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment