Skip to content

Commit 9eb2439

Browse files
committed
feat: provide support for groupby
Signed-off-by: Muhammad Aaqil <[email protected]>
1 parent ae3cf25 commit 9eb2439

File tree

4 files changed

+82
-0
lines changed

4 files changed

+82
-0
lines changed

lib/connectors/memory.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,41 @@ Memory.prototype._findAllSkippingIncludes = function(model, filter) {
502502
// limit/skip
503503
const skip = filter.skip || filter.offset || 0;
504504
const limit = filter.limit || nodes.length;
505+
// groupBy
505506
nodes = nodes.slice(skip, skip + limit);
507+
if (filter.groupBy) {
508+
nodes = utils.groupBy(nodes, filter.groupBy);
509+
const tempNodes = [];
510+
Object.keys(nodes).forEach(nodeKey => {
511+
let count = undefined;
512+
const tempNode = {...nodes[nodeKey][0]};
513+
if (filter.count) {
514+
count = nodes[nodeKey].filter((obj) => {
515+
const id = obj[filter.count];
516+
return obj[filter.count] === id;
517+
}).length;
518+
tempNode.count = count;
519+
}
520+
if (filter.max) {
521+
tempNode.max = Math.max(...nodes[nodeKey].map(o => o[filter.max]));
522+
}
523+
if (filter.min) {
524+
tempNode.min = Math.min(...nodes[nodeKey].map(o => o[filter.min]));
525+
}
526+
if (filter.sum) {
527+
tempNode.sum = nodes[nodeKey].reduce((accumulator, object) => {
528+
return accumulator + object[filter.sum];
529+
}, 0);
530+
}
531+
if (filter.avg) {
532+
tempNode.avg = nodes[nodeKey].reduce((accumulator, object) => {
533+
return accumulator + object[filter.avg];
534+
}, 0);
535+
tempNode.avg = tempNode.avg / nodes[nodeKey].length;
536+
}
537+
});
538+
nodes = tempNodes;
539+
}
506540
}
507541
return nodes;
508542

lib/dao.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,18 @@ DataAccessObject.find = function find(query, options, cb) {
19301930
}
19311931
}
19321932

1933+
const keys = Object.keys(data);
1934+
keys.forEach(key => {
1935+
if (
1936+
key.includes('sumOf') ||
1937+
key.includes('countOf') ||
1938+
key.includes('avgOf') ||
1939+
key.includes('minOf') ||
1940+
key.includes('maxOf')
1941+
) {
1942+
obj.__data[key] = data[key];
1943+
}
1944+
});
19331945
callback(null, obj);
19341946
}
19351947

lib/utils.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ exports.idsHaveDuplicates = idsHaveDuplicates;
3131
exports.isClass = isClass;
3232
exports.escapeRegExp = escapeRegExp;
3333
exports.applyParentProperty = applyParentProperty;
34+
exports.groupBy = groupBy;
3435

3536
const g = require('strong-globalize')();
3637
const traverse = require('traverse');
@@ -893,3 +894,16 @@ function applyParentProperty(element, parent) {
893894
});
894895
}
895896
}
897+
898+
function groupBy(items, key) {
899+
return items.reduce(
900+
(result, item) => ({
901+
...result,
902+
[item[key]]: [
903+
...(result[item[key]] || []),
904+
item,
905+
],
906+
}),
907+
{},
908+
);
909+
}

test/crud-with-options.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,28 @@ describe('crud-with-options', function() {
272272
User.find({limit: 3});
273273
});
274274

275+
it('should allow filter with groupBy, count, max, min, sum & avg', function(done) {
276+
User.find({
277+
groupBy: ['vip'],
278+
count: 'vip',
279+
max: 'id',
280+
min: 'id',
281+
sum: 'id',
282+
avg: 'id',
283+
}, options, function(err, users) {
284+
should.not.exist(err);
285+
should.exist(users);
286+
users.forEach(user => {
287+
user.should.have.property('count', user.count);
288+
user.should.have.property('max');
289+
user.should.have.property('min');
290+
user.should.have.property('sum');
291+
user.should.have.property('avg');
292+
});
293+
done();
294+
});
295+
});
296+
275297
it('should skip trailing undefined args', function(done) {
276298
User.find({limit: 3}, function(err, users) {
277299
should.exists(users);

0 commit comments

Comments
 (0)