UNPKG

mingo

Version:

MongoDB query language for in-memory objects

47 lines (46 loc) 1.31 kB
import { assert, findInsertIndex, has, isArray, isNumber, isObject } from "../../util"; import { errInvalidArgs } from "../expression/_internal"; import { $push } from "./push"; const $percentile = (coll, expr, options) => { assert( isObject(expr) && has(expr, "input", "p") && isArray(expr.p), "$percentile expects object { input, p }" ); const X = $push(coll, expr.input, options).filter(isNumber).sort(); const centiles = $push(expr.p, "$$CURRENT", options); const method = expr.method || "approximate"; const output = new Array(centiles.length); for (let i = 0; i < centiles.length; i++) { const p = centiles[i]; if (!isNumber(p) || p < 0 || p > 1) { return errInvalidArgs( options.failOnError, "$percentile 'p' must resolve to array of numbers between [0.0, 1.0]" ); } const r = p * (X.length - 1) + 1; const ri = Math.floor(r); const result = r === ri ? X[r - 1] : X[ri - 1] + r % 1 * (X[ri] - X[ri - 1]); switch (method) { case "exact": output[i] = result; break; case "approximate": { const pos = findInsertIndex(X, result); output[i] = pos / X.length >= p ? X[Math.max(pos - 1, 0)] : X[pos]; break; } } } return output; }; export { $percentile };