Skip to content

Instantly share code, notes, and snippets.

@maumercado
Last active January 16, 2019 03:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maumercado/53d4817952b1ceccff32 to your computer and use it in GitHub Desktop.
Save maumercado/53d4817952b1ceccff32 to your computer and use it in GitHub Desktop.
batchinate or pagination by batches
require('rootpath')();
var mongoose = require('mongoose');
var async = require('async');
var _ = require('lodash');
var Query = mongoose.Query;
Query.prototype._batchinate = function(options, callback) {
var query = this;
var model = query.model;
model.count(query._conditions, function (err, itemCount){
query.limit(options.count).exec(function(err, results) {
if (err) {
callback(err, {});
return;
}
results = results || [];
if (results[results.length - 1]) {
var maxId = (results[results.length - 1])[options.criteria.split(".")[0]][options.criteria.split(".")[1]] || (results[results.length - 1])[options.criteria];
if (typeof maxId === 'object') maxId = maxId._id;
} else {
var maxId = null;
}
itemsRemaining = itemCount - results.length;
var pager = {
'count': parseInt(options.count, 10),
'results': results,
'itemsRemaining': itemsRemaining < 0 ? 0 : itemsRemaining,
'maxId': maxId,
'sinceId': options.sinceId || null
};
if (pager['maxId'] === null) {
delete pager['maxId'];
}
if (pager['sinceId'] === null) {
delete pager['sinceId'];
}
callback(null, pager);
});
});
};
Query.prototype.batchinate = function(options, callback) {
var defaults = {
sortBy : { '_id' : -1 }, // Field to sort by
sinceId : null, // Offset by this object
maxId : null, // Offset by this object
count : 20, // Number of items to display on each page.
criteria : "_id", // To find documents that match a set of selection criteria.
};
options = options || defaults;
if (options.sortBy) {
var sortFields = options.sortBy.split(",");
options.sortBy = {};
sortFields.forEach(function(sortedValue) {
options.sortBy[sortedValue] = -1;
})
} else {
options.sortBy = defaults.sortBy;
}
options.sinceId = options.sinceId || defaults.sinceId;
options.maxId = options.maxId || defaults.maxId;
if(options.count > 100){
options.count = 100;
}
options.count = options.count || defaults.count;
options.criteria = options.criteria || defaults.criteria;
// Initializing query object
options.objectQuery = {};
options.objectQueryMax = {};
options.objectQuerySince = {};
if (options.sinceId) options.objectQuerySince[options.criteria] = options.sinceId;
if (options.maxId) options.objectQueryMax[options.criteria] = options.maxId;
// #######
var query = this;
var model = query.model;
if (!_.isEmpty(options.maxId) && !_.isEmpty(options.sinceId)) {
async.parallel(
[
function (p_cb) {
model.findOne(options.objectQueryMax, function (err, object) {
if (err) p_cb(err);
if (object) {
p_cb(null, object);
} else {
p_cb(null, {});
}
});
},
function (p_cb) {
model.findOne(options.objectQuerySince, function (err, object) {
if (err) p_cb(err);
if (object) {
p_cb(null, object);
} else {
p_cb(null, {});
}
});
}
],
function (err, objects) {
if (err) query.sort(options.sortBy)._batchinate(options, callback)
if (objects) { // first object is the maxId object, second object is the sinceId object
Object.keys(options.sortBy).forEach(function (value) {
from_object_sortable = objects[0].model ? objects[0][value] : {};
since_object_sortable = objects[1].model ? objects[1][value] : {};
query.find()
.where(value).lt(from_object_sortable).gt(since_object_sortable)
.sort(options.sortBy)._batchinate(options, callback);
});
}
}
); // end async parallel
} else if (!_.isEmpty(options.maxId) || !_.isEmpty(options.sinceId) ) {
options.objectQuery = options.maxId ? options.objectQueryMax : options.objectQuerySince; // query builder
model.findOne(options.objectQuery, function (err, object) {
if (err) {
callback(err, {});
return;
}
if (object) {
if ( !_.isEmpty(options.maxId) ) {
Object.keys(options.sortBy).forEach(function (value) {
query.where(value).lt(object[value]);
});
} else {
Object.keys(options.sortBy).forEach(function (value) {
query.where(value).gt(object[value]);
});
}
query.sort(options.sortBy)._batchinate(options, callback)
} else {
query.sort(options.sortBy)._batchinate(options, callback)
}
});
} else {
query.sort(options.sortBy)._batchinate(options, callback)
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment