mongodb-aggregate-builder
Version:
Builder for generate aggregation query for MongoDB
434 lines (433 loc) • 10.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AggregateBuilder = void 0;
const types_1 = require("./types");
class AggregateBuilder {
constructor() {
this.aggregate = [];
}
/**
* @param groupBy
* @param boundaries
* @param defaultValue
* @param output
*/
bucket(groupBy, boundaries, defaultValue, output) {
this.aggregate.push({
$bucket: {
groupBy,
boundaries,
default: defaultValue,
output
}
});
return this;
}
/**
* @param groupBy
* @param buckets
* @param output
* @param granularity
*/
bucketAuto(groupBy, buckets, output = {}, granularity = '') {
const bucketData = {
groupBy,
buckets
};
if (output !== null && output !== undefined && Object.keys(output).length > 0) {
bucketData['output'] = output;
}
if (granularity) {
bucketData['granularity'] = granularity;
}
this.aggregate.push({
$bucketAuto: bucketData
});
return this;
}
/**
* @param allChangesForCluster
* @param fullDocument
* @param fullDocumentBeforeChange
* @param resumeAfter
* @param showExpandedEvents
* @param startAfter
* @param startAtOperationTime
*/
changeStream(allChangesForCluster, fullDocument, fullDocumentBeforeChange, resumeAfter, showExpandedEvents, startAfter, startAtOperationTime) {
const changeStreamData = {};
// TODO implement this later
this.aggregate.push({
$changeStream: changeStreamData
});
return this;
}
/**
* @param documentsExpression
*/
documents(documentsExpression) {
this.aggregate.push({
$documents: documentsExpression
});
return this;
}
/**
* @param facet
*/
facet(facet) {
this.aggregate.push({
$facet: facet
});
return this;
}
/**
* @param densifyData
*/
densify(densifyData) {
this.aggregate.push({
$densify: densifyData
});
return this;
}
/**
* @param fillData
*/
fill(fillData) {
this.aggregate.push({
$fill: fillData
});
return this;
}
/**
* @param geoExpression
*/
geoNear(geoExpression) {
if (this.aggregate.length > 0) {
throw new Error('geoNear must be the first stage in the pipeline');
}
this.aggregate.push({
$geoNear: geoExpression
});
return this;
}
/**
* @param from
* @param startWith
* @param connectFromField
* @param connectToField
* @param as
* @param maxDepth
* @param depthField
* @param restrictSearchWithMatch
*/
graphLookup(from, startWith, connectFromField, connectToField, as, maxDepth = 0, depthField = '', restrictSearchWithMatch = {}) {
const graphLookupData = {
from,
startWith,
connectFromField,
connectToField,
as,
};
if (maxDepth < 0) {
throw new Error('Max depth must be greater than 0');
}
else if (maxDepth > 0) {
graphLookupData['maxDepth'] = maxDepth;
}
if (depthField) {
graphLookupData['depthField'] = depthField;
}
if (Object.keys(restrictSearchWithMatch).length > 0) {
graphLookupData['restrictSearchWithMatch'] = restrictSearchWithMatch;
}
this.aggregate.push({
$graphLookup: graphLookupData
});
return this;
}
/**
* @param from
* @param localField
* @param foreignField
* @param as
* @param pipeline
*/
lookup(from, localField, foreignField, as, pipeline = []) {
const lookupData = {
from,
localField,
foreignField,
as
};
if (pipeline.length > 0) {
lookupData['pipeline'] = pipeline;
}
this.aggregate.push({
$lookup: lookupData
});
return this;
}
/**
* @param into
* @param on
* @param letVariables
* @param whenMatched
* @param whenNotMatched
*/
merge(into, on = '', letVariables = null, whenMatched = types_1.WhenMatched.MERGE, whenNotMatched = types_1.WhenNotMatched.INSERT) {
const mergeData = {
into
};
if (on) {
mergeData['on'] = on;
}
if (letVariables) {
mergeData['let'] = letVariables;
}
if (whenMatched) {
mergeData['whenMatched'] = whenMatched;
}
if (whenNotMatched) {
mergeData['whenNotMatched'] = whenNotMatched;
}
this.aggregate.push({
$merge: mergeData
});
return this;
}
/**
* @param db
* @param collection
*/
out(db, collection) {
this.aggregate.push({
$out: {
db,
coll: collection
}
});
return this;
}
/**
* @param size
*/
sample(size) {
if (size < 1) {
throw new Error('Size must be greater than 0');
}
this.aggregate.push({
$sample: {
size
}
});
return this;
}
/**
* @param output
* @param partitionBy
* @param sortBy
* @param window
* @param documents
* @param range
* @param unit
*/
setWindowFields(output, partitionBy = '', sortBy = null, window = null, documents = null, range = null, unit = null) {
const setWindowFieldsData = {
output
};
if (partitionBy) {
setWindowFieldsData['partitionBy'] = partitionBy;
}
if (sortBy) {
setWindowFieldsData['sortBy'] = sortBy;
}
if (window) {
setWindowFieldsData['window'] = window;
}
if (documents) {
setWindowFieldsData['documents'] = documents;
}
if (range) {
setWindowFieldsData['range'] = range;
}
if (unit) {
setWindowFieldsData['unit'] = unit;
}
this.aggregate.push({
$setWindowFields: setWindowFieldsData
});
return this;
}
unionWith(coll, pipeline) {
this.aggregate.push({
$unionWith: {
coll,
pipeline
}
});
return this;
}
unwind(path, preserveNullAndEmptyArrays = false) {
this.aggregate.push({
$unwind: {
path,
preserveNullAndEmptyArrays
}
});
return this;
}
/**
* @param fields
*/
unset(fields) {
this.aggregate.push({
$unset: fields
});
return this;
}
project(fields) {
this.aggregate.push({
$project: fields
});
return this;
}
addFields(fields) {
this.aggregate.push({
$addFields: fields
});
return this;
}
/**
*
* @param newRoot
*/
replaceRoot(newRoot) {
this.aggregate.push({
$replaceRoot: {
newRoot
}
});
return this;
}
/**
* @param newRoot
*/
replaceWith(newRoot) {
this.aggregate.push({
$replaceWith: newRoot
});
return this;
}
/**
* @param query
*/
match(query) {
this.aggregate.push({
$match: query
});
return this;
}
/**
* @param fields
*/
group(fields) {
this.aggregate.push({
$group: fields
});
return this;
}
/**
* @param fields
*/
set(fields) {
this.aggregate.push({
$set: fields
});
return this;
}
/**
* @param skipValue
*/
skip(skipValue) {
this.aggregate.push({
$skip: skipValue
});
return this;
}
/**
* @param limit
*/
limit(limit) {
this.aggregate.push({
$limit: limit
});
return this;
}
/**
* @param expression
*/
sortByCount(expression) {
this.aggregate.push({
$sortByCount: expression
});
return this;
}
/**
* @param sort
*/
sort(sort) {
const sortRules = {};
Object.keys(sort).forEach(key => {
if (sort[key] === types_1.SortDirection.TEXT_SCORE) {
sortRules[key] = { $meta: types_1.SortDirection.TEXT_SCORE };
}
else if (sort[key] === types_1.SortDirection.ASC_TEXT || sort[key] === types_1.SortDirection.ASC) {
sortRules[key] = types_1.SortDirection.ASC;
}
else if (sort[key] === types_1.SortDirection.DESC_TEXT || sort[key] === types_1.SortDirection.DESC) {
sortRules[key] = types_1.SortDirection.DESC;
}
});
this.aggregate.push({
$sort: sortRules
});
return this;
}
/**
* @param countName
*/
count(countName) {
this.aggregate.push({
$count: countName
});
return this;
}
/**
* Merge several part of aggregation in one
* @param aggregate
*/
mergeAggregation(aggregate) {
let mergedRules = [];
for (const rule of aggregate) {
mergedRules = [...mergedRules, ...rule];
}
return mergedRules;
}
/**
* Merge several part of aggregation in one with current state
* @param aggregate
*/
mergeAggregationWithCurrent(aggregate) {
for (const rule of aggregate) {
this.aggregate = [...this.aggregate, ...rule];
}
return this;
}
/**
* Return prepared aggregate
*/
build() {
return this.aggregate;
}
}
exports.AggregateBuilder = AggregateBuilder;