@conpago/mongo-cursor-pagination
Version:
Make it easy to return cursor-paginated results from a Mongo collection
111 lines • 4.03 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const underscore_1 = require("underscore");
const config_1 = __importDefault(require("./config"));
const bsonUrlEncoding_1 = require("./utils/bsonUrlEncoding");
/**
* Performs a search query on a Mongo collection and pages the results. This is different from
* find() in that the results are ordered by their relevancy, and as such, it does not take
* a paginatedField parameter. Note that this is less performant than find() because it must
* perform the full search on each call to this function.
*
* @param {Collection} collection A collection object returned from the MongoDB library's. This MUST have a Mongo
* $text index on it.
* See https://docs.mongodb.com/manual/core/index-text/.
* @param {String} searchString String to search on.
* @param {QueryParams} params
* @param {object} params.query The find query.
* @param {Number} params.limit The page size. Must be between 1 and `config.MAX_LIMIT`.
* @param {object} params.fields Fields to query in the Mongo object format, e.g. {title :1}.
* The default is to query ONLY _id (note this is a difference from `find()`).
* @param {String} params.next The value to start querying the page. Defaults to start at the beginning of
* the results.
*/
exports.default = async (collection, searchString, params) => {
if (typeof params.limit === "string")
params.limit = parseInt(params.limit, 10);
if (params.next)
params.next = (0, bsonUrlEncoding_1.decode)(params.next);
params = (0, underscore_1.defaults)(params, {
query: {},
limit: config_1.default.MAX_LIMIT,
});
if (params.limit < 1)
params.limit = 1;
if (params.limit > config_1.default.MAX_LIMIT)
params.limit = config_1.default.MAX_LIMIT;
// We must perform an aggregate query since Mongo can't query a range when using $text search.
const aggregate = [
{
$match: (0, underscore_1.extend)({}, params.query, {
$text: {
$search: searchString,
},
}),
},
{
$project: (0, underscore_1.extend)({}, params.fields, {
_id: 1,
score: {
$meta: "textScore",
},
}),
},
{
$sort: {
score: {
$meta: "textScore",
},
_id: -1,
},
},
];
if (params.next) {
aggregate.push({
$match: {
$or: [
{
score: {
$lt: params.next[0],
},
},
{
score: {
$eq: params.next[0],
},
_id: {
$lt: params.next[1],
},
},
],
},
});
}
aggregate.push({
$limit: params.limit,
});
let response;
// Support both the native 'mongodb' driver and 'mongoist'. See:
// https://www.npmjs.com/package/mongoist#cursor-operations
const aggregateMethod = collection.aggregateAsCursor
? "aggregateAsCursor"
: "aggregate";
const results = await collection[aggregateMethod](aggregate).toArray();
const fullPageOfResults = results.length === params.limit;
if (fullPageOfResults) {
response = {
results,
next: (0, bsonUrlEncoding_1.encode)([(0, underscore_1.last)(results).score, (0, underscore_1.last)(results)._id]),
};
}
else {
response = {
results,
};
}
return response;
};
//# sourceMappingURL=search.js.map