groupjs_by
Version:
The Javascript library used for aggregate on array of objects
150 lines (143 loc) • 3.84 kB
JavaScript
function getItems(data, key) {
return (data[key] && data[key].items) || [];
}
function isValidArray(array) {
return Array.isArray(array) && array.length > 0;
}
function isPresentinAllColumns(columnName, array) {
return array.every((item) => item.hasOwnProperty(columnName));
}
function map(data, action, alias) {
for (let key of getKeys(data)) {
const items = getItems(data, key);
data[key] = {
...data[key],
[alias]: action(items),
};
}
return data;
}
function throwIfNotValid(alias, columnName) {
if (!alias || !columnName) {
throw Error(
`Please make sure you are passing the correct arguments, "alias" and "columnName" are required`
);
}
}
function Group(array = [], column) {
if (!isValidArray(array)) {
throw Error("array parameter is not a valid array");
}
if (!column) {
throw Error(
"You must provide a column name that should exist in all objects"
);
}
if (!isPresentinAllColumns(column, array)) {
throw Error(`${column} must be present in all objects`);
}
const reduceFn = reduceGroup(column);
let data = array.reduce(reduceFn, {});
return {
data,
sum: function (alias, columnName) {
throwIfNotValid(alias, columnName);
map(
data,
(items) => {
const totalByColum = sumByColumn(columnName);
const total = items.reduce(totalByColum, 0);
return total;
},
alias
);
return this;
},
min: function (alias, columnName) {
throwIfNotValid(alias, columnName);
map(
data,
(items) => Math.min(...items.map((item) => item[columnName])),
alias
);
return this;
},
max: function (alias, columnName) {
throwIfNotValid(alias, columnName);
map(
data,
(items) => Math.max(...items.map((item) => item[columnName])),
alias
);
return this;
},
avg: function (alias, columnName, decimals = 2) {
throwIfNotValid(alias, columnName);
map(
data,
(items) => {
const totalByColum = sumByColumn(columnName);
const total = items.reduce(totalByColum, 0);
return parseFloat((total / items.length).toFixed(decimals));
},
alias
);
return this;
},
distinctCount: function (alias, columnName) {
throwIfNotValid(alias, columnName);
map(data, (items) => countDiffentElements(items, columnName), alias);
return this;
},
where: function (predicate) {
if (typeof predicate !== "function") {
throw Error("Predicate must be a function");
}
for (let key of getKeys(data)) {
data[key].items = data[key].items.filter(predicate);
}
return this;
},
keys: (function (data) {
return getKeys(data);
})(data),
firstGroup: (function (data) {
const keys = getKeys(data);
if (!keys.length) return [];
return data[keys[0]].items;
})(data),
lastGroup: (function (data) {
const keys = getKeys(data);
if (!keys.length) return [];
return data[keys[keys.length - 1]].items;
})(data),
};
}
function getKeys(object) {
return Object.keys(object);
}
function countDiffentElements(array, columnName) {
return array.reduce((result, item) => {
const value = item[columnName];
if (!result.includes(value)) {
result.push(value);
}
return result;
}, []).length;
}
function sumByColumn(column) {
return function (result, item) {
return +result + +item[column];
};
}
function reduceGroup(column) {
return function (result, item) {
const value = item[column];
if (!result[value]) {
result[value] = { items: [] };
}
result[value].items.push(item);
return result;
};
}
module.exports = Group;