fix: MongoDB aggregation pipeline with $dateSubtract from $$NOW returns no results (#9822)
This commit is contained in:
@@ -439,6 +439,36 @@ describe('Parse.Query Aggregate testing', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it_id('3723671d-4100-4103-ad9c-60e4c22e20ff')(it_exclude_dbs(['postgres']))('matches expression with $dateSubtract from $$NOW', async () => {
|
||||||
|
const obj1 = new TestObject({ date: new Date(new Date().getTime() - 1 * 24 * 60 * 60 * 1_000) }); // 1 day ago
|
||||||
|
const obj2 = new TestObject({ date: new Date(new Date().getTime() - 2 * 24 * 60 * 60 * 1_000) }); // 3 days ago
|
||||||
|
await Parse.Object.saveAll([obj1, obj2]);
|
||||||
|
|
||||||
|
const pipeline = [
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
$expr: {
|
||||||
|
$gte: [
|
||||||
|
'$date',
|
||||||
|
{
|
||||||
|
$dateSubtract: {
|
||||||
|
startDate: '$$NOW',
|
||||||
|
unit: 'day',
|
||||||
|
amount: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const query = new Parse.Query('TestObject');
|
||||||
|
const results = await query.aggregate(pipeline, { useMasterKey: true });
|
||||||
|
expect(results.length).toBe(1);
|
||||||
|
expect(new Date(results[0].date.iso)).toEqual(obj1.get('date'));
|
||||||
|
});
|
||||||
|
|
||||||
it_only_db('postgres')(
|
it_only_db('postgres')(
|
||||||
'can group by any date field (it does not work if you have dirty data)', // rows in your collection with non date data in the field that is supposed to be a date
|
'can group by any date field (it does not work if you have dirty data)', // rows in your collection with non date data in the field that is supposed to be a date
|
||||||
done => {
|
done => {
|
||||||
|
|||||||
@@ -960,23 +960,28 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will attempt to convert the provided value to a Date object. Since this is part
|
/**
|
||||||
// of an aggregation pipeline, the value can either be a string or it can be another object with
|
* Recursively converts values to Date objects. Since the passed object is part of an aggregation
|
||||||
// an operator in it (like $gt, $lt, etc). Because of this I felt it was easier to make this a
|
* pipeline and can contain various logic operators (like $gt, $lt, etc), this function will
|
||||||
// recursive method to traverse down to the "leaf node" which is going to be the string.
|
* traverse the object and convert any strings that can be parsed as dates into Date objects.
|
||||||
|
* @param {any} value The value to convert.
|
||||||
|
* @returns {any} The original value if not convertible to Date, or a Date object if it is.
|
||||||
|
*/
|
||||||
_convertToDate(value: any): any {
|
_convertToDate(value: any): any {
|
||||||
if (value instanceof Date) {
|
if (value instanceof Date) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
return new Date(value);
|
return isNaN(Date.parse(value)) ? value : new Date(value);
|
||||||
}
|
}
|
||||||
|
if (typeof value === 'object') {
|
||||||
const returnValue = {};
|
const returnValue = {};
|
||||||
for (const field in value) {
|
for (const field in value) {
|
||||||
returnValue[field] = this._convertToDate(value[field]);
|
returnValue[field] = this._convertToDate(value[field]);
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
return returnValue;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
_parseReadPreference(readPreference: ?string): ?string {
|
_parseReadPreference(readPreference: ?string): ?string {
|
||||||
|
|||||||
Reference in New Issue
Block a user