Skip to content

Support deeply nested pointers in 'containedIn' queries #7414

Closed

Description

@oallouch

New Issue Checklist

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 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

Activity

  1. mtrezza commented on Jun 3, 2021

    @mtrezza
    Member

    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 mean children.child becomes a shorthand for children.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?

  2. oallouch commented on Jun 3, 2021

    @oallouch
    ContributorAuthor

    What I suggest is using children.child as a shorthand for children.child.objectId, like it's actually the case with equalTo.
    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" 😋

  3. mtrezza commented on Jun 3, 2021

    @mtrezza
    Member

    The 2 options without objectId are a more natural way for Parse users to query.

    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?

  4. oallouch commented on Jun 3, 2021

    @oallouch
    ContributorAuthor

    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.

  5. mtrezza commented on Jun 3, 2021

    @mtrezza
    Member

    I like the fact that Parse provides added value without going to much in the way.

    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]).

  6. oallouch commented on Jun 3, 2021

    @oallouch
    ContributorAuthor

    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 :

    function getDatabaseController() {
    	const config = Config.get(Parse.applicationId);
    	return config.database;
    }
    
    async function getMongoCollection(className) {
    	const mongoAdapter = getDatabaseController().adapter;
    	await mongoAdapter.connect();
    	return mongoAdapter.database.collection(className);
    }
    

    Btw, we should get a public API for this 😋. Parse can't (and shouldn't) do everything, it already does so much.

  7. mtrezza commented on Jun 3, 2021

    @mtrezza
    Member

    Would you want to open a PR to add the .containedIn('children.child', [child1]) functionality?

  8. oallouch commented on Jun 3, 2021

    @oallouch
    ContributorAuthor

    I can try...

  9. mtrezza commented on Jun 3, 2021

    @mtrezza
    Member

    Great, I assume the .equalTo('children.child.objectId', child1.id) should give some hints on how to approach it.

  10. oallouch commented on Jun 8, 2021

    @oallouch
    ContributorAuthor

    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.

  11. oallouch commented on Jun 10, 2021

    @oallouch
    ContributorAuthor

    The PR is #7426

  12. oallouch commented on Jun 14, 2021

    @oallouch
    ContributorAuthor

    @mtrezza , tell me if something is missing from the PR

  13. RahulLanjewar93 commented on Apr 29, 2025

    @RahulLanjewar93
    Contributor

    Even i debugged, found the same issue

  14. RahulLanjewar93 commented on Apr 29, 2025

    @RahulLanjewar93
    Contributor

    Ok for anyone wondering this is not a bug anymore since parse v6 check this pr #8209. So you may need to run migration which updates the nested parse related objects (object,dates,etc)

    Maybe we can close this issue.

    EDITED: SEEMS NESTED OBJECTS ARE STORED AS JSON check this comment #8209 (comment)

  15. parseplatformorg commented on May 3, 2025

    @parseplatformorg
    Contributor

    🎉 This change has been released in version 8.2.1-alpha.1

  16. parseplatformorg commented on Jun 1, 2025

    @parseplatformorg
    Contributor

    🎉 This change has been released in version 8.2.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions