From ca43d6dcbd2b174aa4cc72b1177b037a5ab8017d Mon Sep 17 00:00:00 2001 From: srameshr Date: Mon, 9 Mar 2020 16:09:41 +0530 Subject: [PATCH 1/6] Group aggregation supports multiple columns for postgres --- spec/ParseQuery.Aggregate.spec.js | 64 +++++++++++++++---- .../Postgres/PostgresStorageAdapter.js | 28 +++++--- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/spec/ParseQuery.Aggregate.spec.js b/spec/ParseQuery.Aggregate.spec.js index 56b61035dc..dcbc2d9d22 100644 --- a/spec/ParseQuery.Aggregate.spec.js +++ b/spec/ParseQuery.Aggregate.spec.js @@ -47,11 +47,19 @@ const loadTestData = () => { views: 700, size: ['S'], }; + const data5 = { + score: 10, + name: 'baz', + sender: { group: 'B' }, + views: 700, + size: ['S'], + }; const obj1 = new TestObject(data1); const obj2 = new TestObject(data2); const obj3 = new TestObject(data3); const obj4 = new TestObject(data4); - return Parse.Object.saveAll([obj1, obj2, obj3, obj4]); + const obj5 = new TestObject(data5); + return Parse.Object.saveAll([obj1, obj2, obj3, obj4, obj5]); }; const get = function(url, options) { @@ -225,6 +233,32 @@ describe('Parse.Query Aggregate testing', () => { }); }); + it('group by multiple columns ', done => { + const obj1 = new TestObject({ score: 10, views: 12 }); + const obj2 = new TestObject({ score: 10, views: 12 }); + const obj3 = new TestObject({ score: 11, view: 15 }); + 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(2); + done(); + }); + }); + it('group by date object', done => { const obj1 = new TestObject(); const obj2 = new TestObject(); @@ -963,25 +997,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..0c18387f4d 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`; From 182de8e3fce16c46e2a0baef876a4b2c4ad60e58 Mon Sep 17 00:00:00 2001 From: srameshr Date: Mon, 9 Mar 2020 16:09:41 +0530 Subject: [PATCH 2/6] Group aggregation supports multiple columns for postgres --- spec/ParseQuery.Aggregate.spec.js | 8 ++++---- src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/ParseQuery.Aggregate.spec.js b/spec/ParseQuery.Aggregate.spec.js index dcbc2d9d22..7837bdb553 100644 --- a/spec/ParseQuery.Aggregate.spec.js +++ b/spec/ParseQuery.Aggregate.spec.js @@ -234,9 +234,9 @@ describe('Parse.Query Aggregate testing', () => { }); it('group by multiple columns ', done => { - const obj1 = new TestObject({ score: 10, views: 12 }); - const obj2 = new TestObject({ score: 10, views: 12 }); - const obj3 = new TestObject({ score: 11, view: 15 }); + const obj1 = new TestObject(); + const obj2 = new TestObject(); + const obj3 = new TestObject(); const pipeline = [ { group: { @@ -254,7 +254,7 @@ describe('Parse.Query Aggregate testing', () => { return query.aggregate(pipeline); }) .then(results => { - expect(results.length).toEqual(2); + expect(results.length).toEqual(5); done(); }); }); diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 0c18387f4d..651b9962ea 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -2219,7 +2219,7 @@ export class PostgresStorageAdapter implements StorageAdapter { groupValues = value; const groupByFields = []; for (const alias in value) { - if ((typeof value[alias] === 'string') & (value[alias] !== '')) { + if (typeof value[alias] === 'string' && value[alias] !== '') { const source = transformAggregateField(value[alias]); if (!groupByFields.includes(`"${source}"`)) { groupByFields.push(`"${source}"`); From 37e9d3a84ec5c647354d0b83b469855d96ec7b6e Mon Sep 17 00:00:00 2001 From: srameshr Date: Mon, 9 Mar 2020 16:09:41 +0530 Subject: [PATCH 3/6] Group aggregation supports multiple columns for postgres --- spec/ParseQuery.Aggregate.spec.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/spec/ParseQuery.Aggregate.spec.js b/spec/ParseQuery.Aggregate.spec.js index 7837bdb553..f68d76a489 100644 --- a/spec/ParseQuery.Aggregate.spec.js +++ b/spec/ParseQuery.Aggregate.spec.js @@ -47,19 +47,11 @@ const loadTestData = () => { views: 700, size: ['S'], }; - const data5 = { - score: 10, - name: 'baz', - sender: { group: 'B' }, - views: 700, - size: ['S'], - }; const obj1 = new TestObject(data1); const obj2 = new TestObject(data2); const obj3 = new TestObject(data3); const obj4 = new TestObject(data4); - const obj5 = new TestObject(data5); - return Parse.Object.saveAll([obj1, obj2, obj3, obj4, obj5]); + return Parse.Object.saveAll([obj1, obj2, obj3, obj4]); }; const get = function(url, options) { From ce5a031bfeaee489457458775324273f7eb2fba8 Mon Sep 17 00:00:00 2001 From: srameshr Date: Mon, 9 Mar 2020 16:09:41 +0530 Subject: [PATCH 4/6] Group aggregation supports multiple columns for postgres --- src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 651b9962ea..31602afc0d 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -2219,7 +2219,7 @@ export class PostgresStorageAdapter implements StorageAdapter { groupValues = value; const groupByFields = []; for (const alias in value) { - if (typeof value[alias] === 'string' && value[alias] !== '') { + if (typeof value[alias] === 'string' && value[alias]) { const source = transformAggregateField(value[alias]); if (!groupByFields.includes(`"${source}"`)) { groupByFields.push(`"${source}"`); From c80a3111f00807e4fab9d9ab0436dd785b4b12f6 Mon Sep 17 00:00:00 2001 From: srameshr Date: Sun, 15 Mar 2020 12:39:34 +0530 Subject: [PATCH 5/6] Fix aggregation order in postgres --- src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 31602afc0d..95a9714b15 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -2281,7 +2281,8 @@ export class PostgresStorageAdapter implements StorageAdapter { } } } else { - columns.push('*'); + // Ignore ALL selector until cases to do so comes up as it throws error as it sits. + //columns.push('*'); } if (stage.$project) { if (columns.includes('*')) { @@ -2370,7 +2371,7 @@ export class PostgresStorageAdapter implements StorageAdapter { } } - const qs = `SELECT ${columns.join()} FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern} ${groupPattern}`; + const qs = `SELECT ${columns.join()} FROM $1:name ${wherePattern} ${limitPattern} ${skipPattern} ${groupPattern} ${sortPattern}`; debug(qs, values); return this._client .map(qs, values, a => From cadc64fa7bc4f0783b275fa4d32257a6ea07a129 Mon Sep 17 00:00:00 2001 From: srameshr Date: Sun, 15 Mar 2020 12:39:34 +0530 Subject: [PATCH 6/6] Fix aggregation order in postgres --- src/Adapters/Storage/Postgres/PostgresStorageAdapter.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 31602afc0d..4eab962910 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -2280,9 +2280,8 @@ export class PostgresStorageAdapter implements StorageAdapter { } } } - } else { - columns.push('*'); } + if (stage.$project) { if (columns.includes('*')) { columns = []; @@ -2370,7 +2369,11 @@ export class PostgresStorageAdapter implements StorageAdapter { } } - const qs = `SELECT ${columns.join()} FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern} ${groupPattern}`; + let qs = `SELECT ${columns.join()} FROM $1:name ${wherePattern} ${skipPattern} ${groupPattern} ${sortPattern} ${limitPattern}`; + + if (qs.includes('GROUP BY')) { + qs = qs.replace(/(\,\*)/g, ''); + } debug(qs, values); return this._client .map(qs, values, a =>