-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Closed
Labels
state:releasedReleased as stable versionReleased as stable versionstate:released-alphaReleased as alpha versionReleased as alpha version
Description
New Issue Checklist
- [x ] I am not disclosing a vulnerability.
- [x ] I am not just asking a question.
- [x ] I have searched through existing issues.
- [x ] I can reproduce the issue with the latest version of Parse Server.
Issue Description
Querying using "containedIn" in deep nested objects using pointers doesn't seems to work.
Steps to reproduce
See example below.
Actual Outcome
The queries return empty arrays.
Expected Outcome
We expected an array of Parse.Object .
Failing Test Case / Pull Request
- 🤩 I submitted a PR with a fix and a test case.🧐 I submitted a PR with a failing test case.To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
To reproduce the issue, I added this at the end of ParseQuery.spec.js
it('deeply nested Pointers (issue #7413)', async function (done) {
const parent = new Parse.Object('Parent');
const child1 = new Parse.Object('Child');
const child2 = new Parse.Object('Child');
parent.set('children', [
{ child: child1, count: 2 },
{ child: child2, count: 3 },
]);
await parent.save();
const results = await new Parse.Query('Parent')
.containedIn('children.child', [child1])
.find();
expect(results.length).toBe(1);
done();
});
This test passes if I replace the line :
.containedIn('children.child', [child1])
by
.containedIn('children.child.objectId', [child1.id])
Environment
parse-server 4.5.0
Server
- Parse Server version: 4.5.0
- Operating system: Windows and debian
- Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): local Windows and Google App Engine
Database
- System (MongoDB or Postgres): MongoDB
- Database version: 4.4.6
- Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): local and MongoDB Atlas
Client
- SDK (iOS, Android, JavaScript, PHP, Unity, etc): Javascript
- SDK version: 3.2
Logs
Metadata
Metadata
Assignees
Labels
state:releasedReleased as stable versionReleased as stable versionstate:released-alphaReleased as alpha versionReleased as alpha version
Activity
mtrezza commentedon Jun 3, 2021
Thanks for reporting.
I think that makes sense. Are you suggesting that when the
objectId
is omitted, it should be inferred, as a convenience? That would meanchildren.child
becomes a shorthand forchildren.child.objectId
.Or should stating the
children.child.objectId
throw an error?What would currently happen if a custom field is used, e.g.
children.child.myField
. Is that an invalid query or would Parse Server generate a proper MongoDB query?oallouch commentedon Jun 3, 2021
What I suggest is using
children.child
as a shorthand forchildren.child.objectId
, like it's actually the case withequalTo
.children.child.objectId
should also work, like it does today.I just would like it to work like it does with simple Pointer arrays.
To sum up, the actual state is :
✅ .containedIn('children.child.objectId', [child1.id])
❌ .containedIn('children.child', [child1])
✅.equalTo('children.child.objectId', child1.id)
✅.equalTo('children.child', child1)
The 2 options without objectId are a more natural way for Parse users to query.
"Give me the Parent with this Child"
Many of my developers have faced this issue.
It's part of the little caveats we tell new devs when they enter the company, like the infamous "dirty() always returns true for new objects, even if the property doesn't exist" 😋
mtrezza commentedon Jun 3, 2021
I think you are right. I agree that it should be possible to do
.containedIn('children.child', [child1])
.I am less sure about whether we should allow
.containedIn('children.child.objectId', [child1.id])
.Because to me that infers that it would be possible to do
children.child.myCustomField
, which I think it isn't.That's why I wonder if we have anything comparable to "specifying an object ID optionally" in other places in the SDK.
If this is the only exception, we could think about removing this bit - or is there any use?
oallouch commentedon Jun 3, 2021
That would be a breaking change for sure, and I don't think being able to use any Pointer subfield is bad.
I like the fact that Parse provides added value without going to much in the way.
mtrezza commentedon Jun 3, 2021
We are now following a phased deprecation policy to avoid sudden breaking changes. So developers would have time to adapt to a change. We need to maintaining the code base and that means stripping features that are duplicates or provide little value, even if they are breaking changes.
That's why I'm wondering what benefit
.containedIn('children.child.objectId', [child1.id])
provides when this PR adds.containedIn('children.child', [child1])
.oallouch commentedon Jun 3, 2021
Maybe I just have the id.
I can do
.containedIn('children.child.objectId', [childId])
without having to retrieve the object from the base, just to use an id I already have.And it's not only about objectId. Maybe one time, I'd like to get all the Parse.Object documents with an array containing at least a pointer of class Child.
For this, I would use
.containedIn('children.child.className', 'Child')
As I said, I love the way parse-server doesn't get in the way. For example, you can create a Parse.Function or use a direct express route (to download pdf file, for instance). That's what make my clients adopt parse-server. You're not blocked.
I'm curious to know the proportion of parse-server projects that have the equivalent of those few line :
Btw, we should get a public API for this 😋. Parse can't (and shouldn't) do everything, it already does so much.
mtrezza commentedon Jun 3, 2021
Would you want to open a PR to add the
.containedIn('children.child', [child1])
functionality?oallouch commentedon Jun 3, 2021
I can try...
mtrezza commentedon Jun 3, 2021
Great, I assume the
.equalTo('children.child.objectId', child1.id)
should give some hints on how to approach it.oallouch commentedon Jun 8, 2021
I did some tests, and I think I understand the problem now.
I thought equalTo only compared objectId, but it also uses __type and className.
I understand now why you called changing children.child to children.child.objectId a "shorthand".
I found the cause. It's actually a bug in MongoTransform's transformConstraint.
This is what it outputs now.
with equalTo (good result) :
mongoWhere: {
'children.child': { __type: 'Pointer', className: 'Child', objectId: 'BoXaGRlIqO' },
_rperm: { '$in': [ null, '', '' ] }
}
with containedIn (bad result) :
mongoWhere: {
'children.child': { '$in': [ 'Child$BoXaGRlIqO' ] },
_rperm: { '$in': [ null, '', '' ] }
}
I'm preparing the PR.
oallouch commentedon Jun 10, 2021
The PR is #7426
oallouch commentedon Jun 14, 2021
@mtrezza , tell me if something is missing from the PR
9 remaining items