Skip to content

Commit de0259c

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

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

lib/connectors/memory.js

+40
Original file line numberDiff line numberDiff line change
@@ -496,13 +496,53 @@ Memory.prototype._findAllSkippingIncludes = function(model, filter) {
496496

497497
// field selection
498498
if (filter.fields) {
499+
if (filter.count) filter.fields.push('count');
500+
if (filter.max) filter.fields.push('max');
501+
if (filter.min) filter.fields.push('min');
502+
if (filter.sum) filter.fields.push('sum');
503+
if (filter.avg) filter.fields.push('avg');
499504
nodes = nodes.map(utils.selectFields(filter.fields));
500505
}
501506

502507
// limit/skip
503508
const skip = filter.skip || filter.offset || 0;
504509
const limit = filter.limit || nodes.length;
510+
// groupBy
505511
nodes = nodes.slice(skip, skip + limit);
512+
if (filter.groupBy) {
513+
nodes = utils.groupBy(nodes, filter.groupBy);
514+
const tempNodes = [];
515+
Object.keys(nodes).forEach(nodeKey => {
516+
let count = undefined;
517+
const tempNode = {...nodes[nodeKey][0]};
518+
if (filter.count) {
519+
count = nodes[nodeKey].filter((obj) => {
520+
const id = obj[filter.count];
521+
return obj[filter.count] === id;
522+
}).length;
523+
tempNode.count = count;
524+
}
525+
if (filter.max) {
526+
tempNode.max = Math.max(...nodes[nodeKey].map(o => o[filter.max]));
527+
}
528+
if (filter.min) {
529+
tempNode.min = Math.min(...nodes[nodeKey].map(o => o[filter.min]));
530+
}
531+
if (filter.sum) {
532+
tempNode.sum = nodes[nodeKey].reduce((accumulator, object) => {
533+
return accumulator + object[filter.sum];
534+
}, 0);
535+
}
536+
if (filter.avg) {
537+
tempNode.avg = nodes[nodeKey].reduce((accumulator, object) => {
538+
return accumulator + object[filter.avg];
539+
}, 0);
540+
tempNode.avg = tempNode.avg / nodes[nodeKey].length;
541+
}
542+
tempNodes.push(tempNode);
543+
});
544+
nodes = tempNodes;
545+
}
506546
}
507547
return nodes;
508548

lib/dao.js

+12
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

+14
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

+48
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,54 @@ 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.length.should.be.above(0);
287+
users.forEach(user => {
288+
user.should.have.property('count', user.count);
289+
user.should.have.property('max');
290+
user.should.have.property('min');
291+
user.should.have.property('sum');
292+
user.should.have.property('avg');
293+
});
294+
done();
295+
});
296+
});
297+
298+
it('should allow filter with groupBy, aggregate methods and other filters', function(done) {
299+
User.find({
300+
groupBy: ['vip'],
301+
count: 'vip',
302+
max: 'id',
303+
min: 'id',
304+
sum: 'id',
305+
avg: 'id',
306+
limit: 1,
307+
fields: ['name', 'id'],
308+
}, options, function(err, users) {
309+
should.not.exist(err);
310+
should.exist(users);
311+
users.length.should.be.equal(1);
312+
users.forEach(user => {
313+
user.should.have.property('count', user.count);
314+
user.should.have.property('max');
315+
user.should.have.property('min');
316+
user.should.have.property('sum');
317+
user.should.have.property('avg');
318+
});
319+
done();
320+
});
321+
});
322+
275323
it('should skip trailing undefined args', function(done) {
276324
User.find({limit: 3}, function(err, users) {
277325
should.exists(users);

0 commit comments

Comments
 (0)