Skip to content

Commit ca9000e

Browse files
authored
Allow aggregate stages with same name (#637)
* Allow aggregate stages with same name Instead of converting array to json for the payload just pass it though. The pipeline keyword needs to be added to the server. * nit * test update
1 parent 1353997 commit ca9000e

File tree

3 files changed

+51
-17
lines changed

3 files changed

+51
-17
lines changed

integration/test/ParseQueryAggregateTest.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('Parse Aggregate Query', () => {
2525

2626
it('aggregate pipeline object query', (done) => {
2727
const pipeline = {
28-
group: { objectId: '$name' }
28+
group: { objectId: '$name' },
2929
};
3030
const query = new Parse.Query(TestObject);
3131
query.aggregate(pipeline).then((results) => {
@@ -55,6 +55,47 @@ describe('Parse Aggregate Query', () => {
5555
}
5656
});
5757

58+
it('aggregate allow multiple of same stage', async () => {
59+
const pointer1 = new TestObject({ value: 1 });
60+
const pointer2 = new TestObject({ value: 2 });
61+
const pointer3 = new TestObject({ value: 3 });
62+
63+
const obj1 = new TestObject({ pointer: pointer1, name: 'Hello' });
64+
const obj2 = new TestObject({ pointer: pointer2, name: 'Hello' });
65+
const obj3 = new TestObject({ pointer: pointer3, name: 'World' });
66+
67+
const pipeline = [{
68+
match: { name: 'Hello' },
69+
}, {
70+
// Transform className$objectId to objectId and store in new field tempPointer
71+
project: {
72+
tempPointer: { $substr: ['$_p_pointer', 11, -1] }, // Remove TestObject$
73+
},
74+
}, {
75+
// Left Join, replace objectId stored in tempPointer with an actual object
76+
lookup: {
77+
from: 'TestObject',
78+
localField: 'tempPointer',
79+
foreignField: '_id',
80+
as: 'tempPointer',
81+
},
82+
}, {
83+
// lookup returns an array, Deconstructs an array field to objects
84+
unwind: {
85+
path: '$tempPointer',
86+
},
87+
}, {
88+
match: { 'tempPointer.value': 2 },
89+
}];
90+
await Parse.Object.saveAll([pointer1, pointer2, pointer3, obj1, obj2, obj3]);
91+
92+
const query = new Parse.Query(TestObject);
93+
const results = await query.aggregate(pipeline);
94+
95+
expect(results.length).toEqual(1);
96+
expect(results[0].tempPointer.value).toEqual(2);
97+
});
98+
5899
it('distinct query', () => {
59100
const query = new Parse.Query(TestObject);
60101
return query.distinct('score').then((results) => {

src/ParseQuery.js

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -572,30 +572,23 @@ class ParseQuery {
572572
options = options || {};
573573

574574
const aggregateOptions = {
575-
useMasterKey: true
575+
useMasterKey: true,
576576
};
577577
if (options.hasOwnProperty('sessionToken')) {
578578
aggregateOptions.sessionToken = options.sessionToken;
579579
}
580580
const controller = CoreManager.getQueryController();
581-
let stages = {};
582581

583-
if (Array.isArray(pipeline)) {
584-
pipeline.forEach((stage) => {
585-
for (let op in stage) {
586-
stages[op] = stage[op];
587-
}
588-
});
589-
} else if (pipeline && typeof pipeline === 'object') {
590-
stages = pipeline;
591-
} else {
582+
if (!Array.isArray(pipeline) && typeof pipeline !== 'object') {
592583
throw new Error('Invalid pipeline must be Array or Object');
593584
}
594585

586+
const params = { pipeline };
587+
595588
return controller.aggregate(
596589
this.className,
597-
stages,
598-
aggregateOptions
590+
params,
591+
aggregateOptions,
599592
).then((results) => {
600593
return results.results;
601594
});

src/__tests__/ParseQuery-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,7 @@ describe('ParseQuery', () => {
18551855
aggregate(className, params, options) {
18561856
expect(className).toBe('Item');
18571857
expect(params).toEqual({
1858-
group: { objectId: '$name' }
1858+
pipeline: [{ group: { objectId: '$name' } }]
18591859
});
18601860
expect(options).toEqual({ useMasterKey: true });
18611861
return Promise.resolve({
@@ -1880,7 +1880,7 @@ describe('ParseQuery', () => {
18801880
aggregate(className, params, options) {
18811881
expect(className).toBe('Item');
18821882
expect(params).toEqual({
1883-
group: { objectId: '$name' }
1883+
pipeline: { group: { objectId: '$name' } }
18841884
});
18851885
expect(options).toEqual({ useMasterKey: true });
18861886
return Promise.resolve({
@@ -1929,7 +1929,7 @@ describe('ParseQuery', () => {
19291929
aggregate(className, params, options) {
19301930
expect(className).toBe('Item');
19311931
expect(params).toEqual({
1932-
group: { objectId: '$name' }
1932+
pipeline: [{ group: { objectId: '$name' } }]
19331933
});
19341934
expect(options).toEqual({
19351935
useMasterKey: true,

0 commit comments

Comments
 (0)