Skip to content

fix: Parse.Query.containedIn and matchesQuery do not work with nested objects #9738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
May 3, 2025
68 changes: 68 additions & 0 deletions spec/ParseQuery.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5306,4 +5306,72 @@ describe('Parse.Query testing', () => {
expect(score).toEqual([1]);
}, { useMasterKey: true });
});

describe_only_db('mongo')('query nested keys', () => {
it('queries nested key using equalTo', async () => {
const child = new Parse.Object('Child');
child.set('key', 'value');
await child.save();

const parent = new Parse.Object('Parent');
parent.set('some', {
nested: {
key: {
child,
},
},
});
await parent.save();

const query1 = await new Parse.Query('Parent')
.equalTo('some.nested.key.child', child)
.find();

expect(query1.length).toEqual(1);
});

it('queries nested key using containedIn', async () => {
const child = new Parse.Object('Child');
child.set('key', 'value');
await child.save();

const parent = new Parse.Object('Parent');
parent.set('some', {
nested: {
key: {
child,
},
},
});
await parent.save();

const query1 = await new Parse.Query('Parent')
.containedIn('some.nested.key.child', [child])
.find();

expect(query1.length).toEqual(1);
});

it('queries nested key using matchesQuery', async () => {
const child = new Parse.Object('Child');
child.set('key', 'value');
await child.save();

const parent = new Parse.Object('Parent');
parent.set('some', {
nested: {
key: {
child,
},
},
});
await parent.save();

const query1 = await new Parse.Query('Parent')
.matchesQuery('some.nested.key.child', new Parse.Query('Child').equalTo('key', 'value'))
.find();

expect(query1.length).toEqual(1);
});
});
});
9 changes: 6 additions & 3 deletions src/Adapters/Storage/Mongo/MongoTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ function transformQueryKeyValue(className, key, value, schema, count = false) {
}

// Handle query constraints
const transformedConstraint = transformConstraint(value, field, count);
const transformedConstraint = transformConstraint(value, field, key, count);
if (transformedConstraint !== CannotTransform) {
if (transformedConstraint.$text) {
return { key: '$text', value: transformedConstraint.$text };
Expand Down Expand Up @@ -651,12 +651,15 @@ function transformTopLevelAtom(atom, field) {
// If it is not a valid constraint but it could be a valid something
// else, return CannotTransform.
// inArray is whether this is an array field.
function transformConstraint(constraint, field, count = false) {
function transformConstraint(constraint, field, queryKey, count = false) {
const inArray = field && field.type && field.type === 'Array';
// Check wether the given key has `.`
const isNestedKey = queryKey.indexOf('.') > -1;
if (typeof constraint !== 'object' || !constraint) {
return CannotTransform;
}
const transformFunction = inArray ? transformInteriorAtom : transformTopLevelAtom;
// For inArray or nested key, we need to transform the interior atom
const transformFunction = (inArray || isNestedKey) ? transformInteriorAtom : transformTopLevelAtom;
const transformer = atom => {
const result = transformFunction(atom, field);
if (result === CannotTransform) {
Expand Down
Loading