Open zurmokeeper opened 10 months ago
I am having the same problem
I'm updating an older Parse 5.2.x server running against MongoDB 4.4. I noticed this deprecation warning in my logs:
DeprecationWarning: Using aggregation stages without a leading '$' is deprecated and will be removed in a future version. Try $distinct instead.
Could your error be related to this? If you are running MongoDB 5 or higher maybe they no longer support distinct queries without the leading '$'.
I came here to validate that a new parse server implemented this change. BTW, your description says you are running Parse Server 6.3.1 but the extra details say Parse Server 5.6.1. Can you verify that?
Are you in a position to test this against MongoDB 4.4 and/or against the latest Parse Server?
Following up on my comment above, I can verify that these issues are related. I updated my Parse Server 5.2.x server all the way to MongoDB 7.x and still received the DeprecationWarning. Everything worked though.
Next, I upgraded to the latest 5.6.x Parse Server and everything was working.
Finally, I upgraded to latest Parse Server 6.4.x and now I get the same error as described in the initial bug report. I rolled back to 6.0.x and confirmed the bug was introduced between 5.6 -> 6.0.
I am using a distinct query on an object pointer in Cloud Code if that helps narrow it down. I'll keep digging as well.
Update
distinct
method not converting to mongo pipelines in the AggregateRouter correctly. I tried to locate the bug but gave up after a while. My pseudocode:
...
var games = Parse.Object.extend('Games')
var query = new Parse.Query(games)
query.equalTo('stadiumRef', stadiumRef); // stadiumRef is an object pointer to a record in the stadiums collection
query.hint('teamRef'); // <== Adding this fixes my distinct query in Parse Server >=6.0
// Get count of distinct team's that have played a game in the stadium
query.distinct('teamRef', {useMasterKey: true})
.then(function(results) {
....
@chadpav Would you want to open a PR with a failing test, and do you have a suggestion for a bug fix? Once we have a failing test we can also put a bounty to expedite the fixing.
I have a work around and I did try to dig into the server code but it's a little beyond my skillset to do so. Hopefully I've narrowed down the reproduction steps for you guys.
It happens because ParseQuery.distinct,aggregate
in Parse-SDK-JS usually sends hint: undefined
to AggregateRouter.handleFind
which does not remove the hint from the request body unless it holds a value then it's passed to AggregateRouter.getPipeline(body);
.
It has been modified to make sure aggregate operators are preceded by a $
which is not the case for hint: undefiend
hence the invalid aggregate stage error is thrown.
Original code:
handleFind(req) {
const body = Object.assign(req.body, ClassesRouter.JSONFromQuery(req.query));
const options = {};
if (body.distinct) {
options.distinct = String(body.distinct);
}
if (body.hint) {
options.hint = body.hint;
delete body.hint;
}
if (body.explain) {
options.explain = body.explain;
delete body.explain;
}
if (body.comment) {
options.comment = body.comment;
delete body.comment;
}
if (body.readPreference) {
options.readPreference = body.readPreference;
delete body.readPreference;
}
options.pipeline = AggregateRouter.getPipeline(body);
if (typeof body.where === 'string') {
body.where = JSON.parse(body.where);
}
return rest
.find(
req.config,
req.auth,
this.className(req),
body.where,
options,
req.info.clientSDK,
req.info.context
)
.then(response => {
for (const result of response.results) {
if (typeof result === 'object') {
UsersRouter.removeHiddenProperties(result);
}
}
return { response };
});
}
A fix:
handleFind(req) {
const body = Object.assign(req.body, ClassesRouter.JSONFromQuery(req.query));
const options = {};
if (body.distinct) {
options.distinct = String(body.distinct);
}
['hint', 'explain', 'comment', 'readPreference'].forEach(key => {
if (body[key]) options[key] = body[key];
delete body[key];
});
options.pipeline = AggregateRouter.getPipeline(body);
if (typeof body.where === 'string') {
body.where = JSON.parse(body.where);
}
return rest
.find(
req.config,
req.auth,
this.className(req),
body.where,
options,
req.info.clientSDK,
req.info.context
)
.then(response => {
for (const result of response.results) {
if (typeof result === 'object') {
UsersRouter.removeHiddenProperties(result);
}
}
return { response };
});
}
A test:
const Config = require('../lib/Config');
const ClientSDK = require('../lib/ClientSDK');
it('"handleFind" properly handles "req.body.hint" and invalid aggregate stage error should not be thrown', async () => {
const config = Config.get('test');
const clientSDK = ClientSDK.fromString('i0.0.0');
const req = {
config,
params: { className: '_User' },
body: {
distinct: 'first_name',
where: {
objectId: 'someId',
},
hint: undefined,
},
info: {
clientSDK,
context: '1',
},
auth: { readOnly: false },
};
const expected = { response: { results: [] } };
const aggregateRouter = new AggregateRouter();
const result = await aggregateRouter.handleFind(req);
expect(result).toEqual(expected);
});
@Chilldev would you want to submit a PR with a failing test?
@mtrezza Sure. Let me check the contribution guide.
The issue occures when directAccess is set to true and the distinct query is wrapped within an eachBatch.
I wrote the test but for it to work I have to comment this line:
Parse.CoreManager.setRESTController(RESTController);
The error occures because this is what naturally happens when parse server started withdirectAccess
set to true:
if (process.env.PARSE_SERVER_ENABLE_EXPERIMENTAL_DIRECT_ACCESS === '1' || directAccess) { Parse.CoreManager.setRESTController(ParseServerRESTController(appId, appRouter)); }
ParseServer
rest controller is diffrent from Parse-JS-SDK
I suppose which makes it access the AggregateController directly instead of SchemaController.
New Issue Checklist
Issue Description
const distinctResult = await query.distinct("score");
parse-server v6.3.1 This code will give you an error.
ParseError: Invalid aggregate stage 'hint'.
Steps to reproduce
Actual Outcome
ParseError: Invalid aggregate stage 'hint'.
Expected Outcome
no error message
Environment
Server
V6.3.1
win11
local
Database
MongoDB
5.0
Local
Just use the third release tool to request it directly
Logs
Some Detail