feat(AggregateRouter): support native mongodb syntax in aggregation pipelines (#7339)
This commit is contained in:
committed by
GitHub
parent
381e9bf014
commit
8fddac39bf
@@ -105,6 +105,7 @@ ___
|
|||||||
- Add official support for MongoDB 5.0 (Manuel Trezza) [#7469](https://github.com/parse-community/parse-server/pull/7469)
|
- Add official support for MongoDB 5.0 (Manuel Trezza) [#7469](https://github.com/parse-community/parse-server/pull/7469)
|
||||||
|
|
||||||
### Other Changes
|
### Other Changes
|
||||||
|
- Support native mongodb syntax in aggregation pipelines (Raschid JF Rafeally) [#7339](https://github.com/parse-community/parse-server/pull/7339)
|
||||||
- Fix error when a not yet inserted job is updated (Antonio Davi Macedo Coelho de Castro) [#7196](https://github.com/parse-community/parse-server/pull/7196)
|
- Fix error when a not yet inserted job is updated (Antonio Davi Macedo Coelho de Castro) [#7196](https://github.com/parse-community/parse-server/pull/7196)
|
||||||
- request.context for afterFind triggers (dblythy) [#7078](https://github.com/parse-community/parse-server/pull/7078)
|
- request.context for afterFind triggers (dblythy) [#7078](https://github.com/parse-community/parse-server/pull/7078)
|
||||||
- Winston Logger interpolating stdout to console (dplewis) [#7114](https://github.com/parse-community/parse-server/pull/7114)
|
- Winston Logger interpolating stdout to console (dplewis) [#7114](https://github.com/parse-community/parse-server/pull/7114)
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
The following is a list of deprecations, according to the [Deprecation Policy](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#deprecation-policy). After a feature becomes deprecated, and giving developers time to adapt to the change, the deprecated feature will eventually be removed, leading to a breaking change. Developer feedback during the deprecation period may postpone the introduction of the breaking change.
|
The following is a list of deprecations, according to the [Deprecation Policy](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#deprecation-policy). After a feature becomes deprecated, and giving developers time to adapt to the change, the deprecated feature will eventually be removed, leading to a breaking change. Developer feedback during the deprecation period may postpone the introduction of the breaking change.
|
||||||
|
|
||||||
| Feature | Issue | Deprecation [ℹ️][i_deprecation] | Planned Removal [ℹ️][i_removal] | Status [ℹ️][i_status] | Notes |
|
| Feature | Issue | Deprecation [ℹ️][i_deprecation] | Planned Removal [ℹ️][i_removal] | Status [ℹ️][i_status] | Notes |
|
||||||
|---------|----|------------------|----------------------|----------|-------|
|
|-----------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
|
||||||
(none)
|
| Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
|
||||||
|
|
||||||
|
|
||||||
[i_deprecation]: ## "The version and date of the deprecation."
|
[i_deprecation]: ## "The version and date of the deprecation."
|
||||||
[i_removal]: ## "The version and date of the planned removal."
|
[i_removal]: ## "The version and date of the planned removal."
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const AggregateRouter = require('../lib/Routers/AggregateRouter').AggregateRouter;
|
const AggregateRouter = require('../lib/Routers/AggregateRouter').AggregateRouter;
|
||||||
|
|
||||||
describe('AggregateRouter', () => {
|
describe('AggregateRouter', () => {
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get pipeline from Array', () => {
|
it('get pipeline from Array', () => {
|
||||||
const body = [
|
const body = [
|
||||||
{
|
{
|
||||||
@@ -12,6 +13,7 @@ describe('AggregateRouter', () => {
|
|||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get pipeline from Object', () => {
|
it('get pipeline from Object', () => {
|
||||||
const body = {
|
const body = {
|
||||||
group: { objectId: {} },
|
group: { objectId: {} },
|
||||||
@@ -21,6 +23,7 @@ describe('AggregateRouter', () => {
|
|||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get pipeline from Pipeline Operator (Array)', () => {
|
it('get pipeline from Pipeline Operator (Array)', () => {
|
||||||
const body = {
|
const body = {
|
||||||
pipeline: [
|
pipeline: [
|
||||||
@@ -34,6 +37,7 @@ describe('AggregateRouter', () => {
|
|||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get pipeline from Pipeline Operator (Object)', () => {
|
it('get pipeline from Pipeline Operator (Object)', () => {
|
||||||
const body = {
|
const body = {
|
||||||
pipeline: {
|
pipeline: {
|
||||||
@@ -45,6 +49,7 @@ describe('AggregateRouter', () => {
|
|||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get pipeline fails multiple keys in Array stage ', () => {
|
it('get pipeline fails multiple keys in Array stage ', () => {
|
||||||
const body = [
|
const body = [
|
||||||
{
|
{
|
||||||
@@ -59,6 +64,7 @@ describe('AggregateRouter', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get pipeline fails multiple keys in Pipeline Operator Array stage ', () => {
|
it('get pipeline fails multiple keys in Pipeline Operator Array stage ', () => {
|
||||||
const body = {
|
const body = {
|
||||||
pipeline: [
|
pipeline: [
|
||||||
@@ -75,6 +81,7 @@ describe('AggregateRouter', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: update pipeline syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
it('get search pipeline from Pipeline Operator (Array)', () => {
|
it('get search pipeline from Pipeline Operator (Array)', () => {
|
||||||
const body = {
|
const body = {
|
||||||
pipeline: {
|
pipeline: {
|
||||||
@@ -85,4 +92,73 @@ describe('AggregateRouter', () => {
|
|||||||
const result = AggregateRouter.getPipeline(body);
|
const result = AggregateRouter.getPipeline(body);
|
||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('support stage name starting with `$`', () => {
|
||||||
|
const body = {
|
||||||
|
$match: { someKey: 'whatever' },
|
||||||
|
};
|
||||||
|
const expected = [{ $match: { someKey: 'whatever' } }];
|
||||||
|
const result = AggregateRouter.getPipeline(body);
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('support nested stage names starting with `$`', () => {
|
||||||
|
const body = [
|
||||||
|
{
|
||||||
|
lookup: {
|
||||||
|
from: 'ACollection',
|
||||||
|
let: { id: '_id' },
|
||||||
|
as: 'results',
|
||||||
|
pipeline: [
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
$expr: {
|
||||||
|
$eq: ['$_id', '$$id'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const expected = [
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: 'ACollection',
|
||||||
|
let: { id: '_id' },
|
||||||
|
as: 'results',
|
||||||
|
pipeline: [
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
$expr: {
|
||||||
|
$eq: ['$_id', '$$id'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const result = AggregateRouter.getPipeline(body);
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('support the use of `_id` in stages', () => {
|
||||||
|
const body = [
|
||||||
|
{ match: { _id: 'randomId' } },
|
||||||
|
{ sort: { _id: -1 } },
|
||||||
|
{ addFields: { _id: 1 } },
|
||||||
|
{ group: { _id: {} } },
|
||||||
|
{ project: { _id: 0 } },
|
||||||
|
];
|
||||||
|
const expected = [
|
||||||
|
{ $match: { _id: 'randomId' } },
|
||||||
|
{ $sort: { _id: -1 } },
|
||||||
|
{ $addFields: { _id: 1 } },
|
||||||
|
{ $group: { _id: {} } },
|
||||||
|
{ $project: { _id: 0 } },
|
||||||
|
];
|
||||||
|
const result = AggregateRouter.getPipeline(body);
|
||||||
|
expect(result).toEqual(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,28 +23,28 @@ const loadTestData = () => {
|
|||||||
const data1 = {
|
const data1 = {
|
||||||
score: 10,
|
score: 10,
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
sender: { group: 'A' },
|
sender: { group: 'A' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
views: 900,
|
views: 900,
|
||||||
size: ['S', 'M'],
|
size: ['S', 'M'],
|
||||||
};
|
};
|
||||||
const data2 = {
|
const data2 = {
|
||||||
score: 10,
|
score: 10,
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
sender: { group: 'A' },
|
sender: { group: 'A' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
views: 800,
|
views: 800,
|
||||||
size: ['M', 'L'],
|
size: ['M', 'L'],
|
||||||
};
|
};
|
||||||
const data3 = {
|
const data3 = {
|
||||||
score: 10,
|
score: 10,
|
||||||
name: 'bar',
|
name: 'bar',
|
||||||
sender: { group: 'B' },
|
sender: { group: 'B' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
views: 700,
|
views: 700,
|
||||||
size: ['S'],
|
size: ['S'],
|
||||||
};
|
};
|
||||||
const data4 = {
|
const data4 = {
|
||||||
score: 20,
|
score: 20,
|
||||||
name: 'dpl',
|
name: 'dpl',
|
||||||
sender: { group: 'B' },
|
sender: { group: 'B' }, // TODO: change to `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
views: 700,
|
views: 700,
|
||||||
size: ['S'],
|
size: ['S'],
|
||||||
};
|
};
|
||||||
@@ -83,22 +83,10 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid query group _id', done => {
|
it('invalid query group _id required', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
group: { _id: null },
|
group: {}, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
|
||||||
});
|
|
||||||
get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
|
|
||||||
expect(error.error.code).toEqual(Parse.Error.INVALID_QUERY);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('invalid query group objectId required', done => {
|
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
|
||||||
body: {
|
|
||||||
group: {},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
|
get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
|
||||||
@@ -110,7 +98,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group by field', done => {
|
it('group by field', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
group: { objectId: '$name' },
|
group: { objectId: '$name' }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
get(Parse.serverURL + '/aggregate/TestObject', options)
|
get(Parse.serverURL + '/aggregate/TestObject', options)
|
||||||
@@ -131,7 +119,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
pipeline: {
|
pipeline: {
|
||||||
group: { objectId: '$name' },
|
group: { objectId: '$name' }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -149,7 +137,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj = new TestObject();
|
const obj = new TestObject();
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
group: { objectId: {} },
|
group: { objectId: {} }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
obj
|
obj
|
||||||
@@ -168,7 +156,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj = new TestObject();
|
const obj = new TestObject();
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
group: { objectId: '' },
|
group: { objectId: '' }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
obj
|
obj
|
||||||
@@ -187,7 +175,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj = new TestObject();
|
const obj = new TestObject();
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
group: { objectId: [] },
|
group: { objectId: [] }, // TODO: write as `$group`. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
obj
|
obj
|
||||||
@@ -208,6 +196,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj3 = new TestObject();
|
const obj3 = new TestObject();
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: {
|
group: {
|
||||||
objectId: {
|
objectId: {
|
||||||
score: '$score',
|
score: '$score',
|
||||||
@@ -234,6 +223,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj3 = new TestObject();
|
const obj3 = new TestObject();
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: {
|
group: {
|
||||||
objectId: {
|
objectId: {
|
||||||
day: { $dayOfMonth: '$_updated_at' },
|
day: { $dayOfMonth: '$_updated_at' },
|
||||||
@@ -264,6 +254,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj3 = new TestObject();
|
const obj3 = new TestObject();
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: {
|
group: {
|
||||||
objectId: {
|
objectId: {
|
||||||
day: { $dayOfMonth: '$updatedAt' },
|
day: { $dayOfMonth: '$updatedAt' },
|
||||||
@@ -291,7 +282,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group by number', done => {
|
it('group by number', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
group: { objectId: '$score' },
|
group: { objectId: '$score' }, // TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
get(Parse.serverURL + '/aggregate/TestObject', options)
|
get(Parse.serverURL + '/aggregate/TestObject', options)
|
||||||
@@ -313,6 +304,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
|
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: {
|
group: {
|
||||||
objectId: null,
|
objectId: null,
|
||||||
total: { $sum: { $multiply: ['$quantity', '$price'] } },
|
total: { $sum: { $multiply: ['$quantity', '$price'] } },
|
||||||
@@ -372,7 +364,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
project: {
|
project: {
|
||||||
objectId: 0,
|
objectId: 0, // TODO: change to `_id`. See [#7339](https://bit.ly/3incnWx)
|
||||||
total: { $multiply: ['$quantity', '$price'] },
|
total: { $multiply: ['$quantity', '$price'] },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -459,6 +451,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const obj3 = new TestObject({ dateField2019: new Date(1990, 11, 1) });
|
const obj3 = new TestObject({ dateField2019: new Date(1990, 11, 1) });
|
||||||
const pipeline = [
|
const pipeline = [
|
||||||
{
|
{
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: {
|
group: {
|
||||||
objectId: {
|
objectId: {
|
||||||
day: { $dayOfMonth: '$dateField2019' },
|
day: { $dayOfMonth: '$dateField2019' },
|
||||||
@@ -508,6 +501,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group sum query', done => {
|
it('group sum query', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, total: { $sum: '$score' } },
|
group: { objectId: null, total: { $sum: '$score' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -524,6 +518,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group count query', done => {
|
it('group count query', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, total: { $sum: 1 } },
|
group: { objectId: null, total: { $sum: 1 } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -540,6 +535,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group min query', done => {
|
it('group min query', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, minScore: { $min: '$score' } },
|
group: { objectId: null, minScore: { $min: '$score' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -556,6 +552,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group max query', done => {
|
it('group max query', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, maxScore: { $max: '$score' } },
|
group: { objectId: null, maxScore: { $max: '$score' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -572,6 +569,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('group avg query', done => {
|
it('group avg query', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, avgScore: { $avg: '$score' } },
|
group: { objectId: null, avgScore: { $avg: '$score' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1017,6 +1015,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
project: { score: 1 },
|
project: { score: 1 },
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: '$score', score: { $sum: '$score' } },
|
group: { objectId: '$score', score: { $sum: '$score' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1044,6 +1043,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('class does not exist return empty', done => {
|
it('class does not exist return empty', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, total: { $sum: '$score' } },
|
group: { objectId: null, total: { $sum: '$score' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1058,6 +1058,7 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
it('field does not exist return empty', done => {
|
it('field does not exist return empty', done => {
|
||||||
const options = Object.assign({}, masterKeyOptions, {
|
const options = Object.assign({}, masterKeyOptions, {
|
||||||
body: {
|
body: {
|
||||||
|
// TODO: update to new syntax. See [#7339](https://bit.ly/3incnWx)
|
||||||
group: { objectId: null, total: { $sum: '$unknownfield' } },
|
group: { objectId: null, total: { $sum: '$unknownfield' } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import rest from '../rest';
|
|||||||
import * as middleware from '../middlewares';
|
import * as middleware from '../middlewares';
|
||||||
import Parse from 'parse/node';
|
import Parse from 'parse/node';
|
||||||
import UsersRouter from './UsersRouter';
|
import UsersRouter from './UsersRouter';
|
||||||
|
import Deprecator from '../Deprecator/Deprecator';
|
||||||
|
|
||||||
export class AggregateRouter extends ClassesRouter {
|
export class AggregateRouter extends ClassesRouter {
|
||||||
handleFind(req) {
|
handleFind(req) {
|
||||||
@@ -91,22 +92,30 @@ export class AggregateRouter extends ClassesRouter {
|
|||||||
|
|
||||||
static transformStage(stageName, stage) {
|
static transformStage(stageName, stage) {
|
||||||
if (stageName === 'group') {
|
if (stageName === 'group') {
|
||||||
if (Object.prototype.hasOwnProperty.call(stage[stageName], '_id')) {
|
if (Object.prototype.hasOwnProperty.call(stage[stageName], 'objectId')) {
|
||||||
throw new Parse.Error(
|
Deprecator.logRuntimeDeprecation({
|
||||||
Parse.Error.INVALID_QUERY,
|
usage: 'The use of objectId in aggregation stage $group',
|
||||||
`Invalid parameter for query: group. Please use objectId instead of _id`
|
solution: 'Use _id instead.',
|
||||||
);
|
});
|
||||||
}
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(stage[stageName], 'objectId')) {
|
|
||||||
throw new Parse.Error(
|
|
||||||
Parse.Error.INVALID_QUERY,
|
|
||||||
`Invalid parameter for query: group. objectId is required`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
stage[stageName]._id = stage[stageName].objectId;
|
stage[stageName]._id = stage[stageName].objectId;
|
||||||
delete stage[stageName].objectId;
|
delete stage[stageName].objectId;
|
||||||
}
|
}
|
||||||
return { [`$${stageName}`]: stage[stageName] };
|
if (!Object.prototype.hasOwnProperty.call(stage[stageName], '_id')) {
|
||||||
|
throw new Parse.Error(
|
||||||
|
Parse.Error.INVALID_QUERY,
|
||||||
|
`Invalid parameter for query: group. Missing key _id`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stageName[0] !== '$') {
|
||||||
|
Deprecator.logRuntimeDeprecation({
|
||||||
|
usage: "Using aggregation stages without a leading '$'",
|
||||||
|
solution: `Try $${stageName} instead.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const key = stageName[0] === '$' ? stageName : `$${stageName}`;
|
||||||
|
return { [key]: stage[stageName] };
|
||||||
}
|
}
|
||||||
|
|
||||||
mountRoutes() {
|
mountRoutes() {
|
||||||
|
|||||||
Reference in New Issue
Block a user