diff --git a/spec/ParseQuery.Aggregate.spec.js b/spec/ParseQuery.Aggregate.spec.js index 56b61035dc..f68d76a489 100644 --- a/spec/ParseQuery.Aggregate.spec.js +++ b/spec/ParseQuery.Aggregate.spec.js @@ -225,6 +225,32 @@ describe('Parse.Query Aggregate testing', () => { }); }); + it('group by multiple columns ', done => { + const obj1 = new TestObject(); + const obj2 = new TestObject(); + const obj3 = new TestObject(); + const pipeline = [ + { + group: { + objectId: { + score: '$score', + views: '$views', + }, + count: { $sum: 1 }, + }, + }, + ]; + Parse.Object.saveAll([obj1, obj2, obj3]) + .then(() => { + const query = new Parse.Query(TestObject); + return query.aggregate(pipeline); + }) + .then(results => { + expect(results.length).toEqual(5); + done(); + }); + }); + it('group by date object', done => { const obj1 = new TestObject(); const obj2 = new TestObject(); @@ -963,25 +989,29 @@ describe('Parse.Query Aggregate testing', () => { await Parse.Object.saveAll([obj1, obj2, obj3, obj4, obj5, obj6]); expect( - (await new Parse.Query('MyCollection').aggregate([ - { - match: { - language: { $in: [null, 'en'] }, + ( + await new Parse.Query('MyCollection').aggregate([ + { + match: { + language: { $in: [null, 'en'] }, + }, }, - }, - ])) + ]) + ) .map(value => value.otherField) .sort() ).toEqual([1, 2, 3, 4]); expect( - (await new Parse.Query('MyCollection').aggregate([ - { - match: { - $or: [{ language: 'en' }, { language: null }], + ( + await new Parse.Query('MyCollection').aggregate([ + { + match: { + $or: [{ language: 'en' }, { language: null }], + }, }, - }, - ])) + ]) + ) .map(value => value.otherField) .sort() ).toEqual([1, 2, 3, 4]); diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 0fc5d4c820..3f32953fa6 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -2219,20 +2219,30 @@ export class PostgresStorageAdapter implements StorageAdapter { groupValues = value; const groupByFields = []; for (const alias in value) { - const operation = Object.keys(value[alias])[0]; - const source = transformAggregateField(value[alias][operation]); - if (mongoAggregateToPostgres[operation]) { + if (typeof value[alias] === 'string' && value[alias]) { + const source = transformAggregateField(value[alias]); if (!groupByFields.includes(`"${source}"`)) { groupByFields.push(`"${source}"`); } - columns.push( - `EXTRACT(${ - mongoAggregateToPostgres[operation] - } FROM $${index}:name AT TIME ZONE 'UTC') AS $${index + - 1}:name` - ); values.push(source, alias); + columns.push(`$${index}:name AS $${index + 1}:name`); index += 2; + } else { + const operation = Object.keys(value[alias])[0]; + const source = transformAggregateField(value[alias][operation]); + if (mongoAggregateToPostgres[operation]) { + if (!groupByFields.includes(`"${source}"`)) { + groupByFields.push(`"${source}"`); + } + columns.push( + `EXTRACT(${ + mongoAggregateToPostgres[operation] + } FROM $${index}:name AT TIME ZONE 'UTC') AS $${index + + 1}:name` + ); + values.push(source, alias); + index += 2; + } } } groupPattern = `GROUP BY $${index}:raw`; @@ -2273,6 +2283,7 @@ export class PostgresStorageAdapter implements StorageAdapter { } else { columns.push('*'); } + if (stage.$project) { if (columns.includes('*')) { columns = []; @@ -2360,7 +2371,18 @@ export class PostgresStorageAdapter implements StorageAdapter { } } - const qs = `SELECT ${columns.join()} FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern} ${groupPattern}`; + if (groupPattern) { + columns.forEach((e, i, a) => { + if (e && e.trim() === '*') { + a[i] = ''; + } + }); + } + + const qs = `SELECT ${columns + .filter(Boolean) + .join()} FROM $1:name ${wherePattern} ${skipPattern} ${groupPattern} ${sortPattern} ${limitPattern}`; + debug(qs, values); return this._client .map(qs, values, a =>