Skip to content
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

GraphQL: How to query data from array of pointers #5894

Closed
murshudov opened this issue Aug 8, 2019 · 9 comments

Comments

@murshudov
Copy link

commented Aug 8, 2019

This is my query

query JobQuery {
  objects {
    getJob(objectId: "sqvJTrN9no") {
      title
      company {
        name
      }
      countries
    }
  }
}

and it returns

{
  "data": {
    "objects": {
      "getJob": {
        "title": "Sales Assistant",
        "company": {
          "name": "Gulfstream Distribution"
        },
        "countries": [
          {
            "__type": "Pointer",
            "className": "Country",
            "objectId": "lZ15JnGq7h"
          }
        ]
      }
    }
  }
}

But I want to get country details inside this query results. Is there a way to do that?

I thought maybe something like this exists:

query JobQuery {
  objects {
    getJob(objectId: "sqvJTrN9no") {
      title
      company {
        name
      }
      countries
    }
    
    findCountry(where: { objectId: { _in: ["lZ15JnGq7h"]} }) {
      results {
        name
      }
    }
  }
}

Result:

{
  "data": {
    "objects": {
      "getJob": {
        "title": "Sales Assistant",
        "company": {
          "name": "Gulfstream Distribution"
        },
        "countries": [
          {
            "__type": "Pointer",
            "className": "Country",
            "objectId": "lZ15JnGq7h"
          }
        ]
      },
      "findCountry": {
        "results": [
          {
            "name": "Azerbaijan"
          }
        ]
      }
    }
  }
}

I don't know how to include results from getJob query into findCountry query. Any help would be appreciated 😊

@davimacedo

This comment has been minimized.

Copy link
Member

commented Aug 8, 2019

It works pretty much like you expect if you have a field that is a Pointer or a Relation. Since it is an Array, and an Array can have any kind of item, the Parse GraphQL Server does not know beforehand what kind of object you have there and can't make its fields automatically available. We can think about some solutions for this. Maybe allow the developer to specify the type of the array? @Moumouls @omairvaiyani @douglasmuraoka

@omairvaiyani

This comment has been minimized.

Copy link
Contributor

commented Aug 9, 2019

One option is to introduce this into the Parse GraphQL Config:

{
 ...
 classConfigs: [
 {
  className: "Country",
  type: {
      pointerArrays: [ {  field: "cities",  className: "City"  }, {  field: "states",  className: "State"  }  ]
  }
 }
] 
 ...
}

Longer-term would be to introduce this knowledge directly into the database schema, although I've not assessed the drawbacks yet.

@davimacedo

This comment has been minimized.

Copy link
Member

commented Aug 9, 2019

@omairvaiyani I like this idea. I am only wondering if this information could be also useful for Parse Server overall. So maybe having this information in the parse server schema would be better?

@omairvaiyani

This comment has been minimized.

Copy link
Contributor

commented Aug 10, 2019

@davimacedo it certainly would be. I understand that the Parse Server _Schema class stores the field type as "array", regardless of whether the array stores regular POJOS, or Parse pointers. The source code also freely allows pointers to be changed from one class to another. If we did introduce a specific type, it would result in stricter behaviour, possibly classified as a breaking change.

A way around this would be to allow the current type "array" to continue behaving exactly as it does today, whilst allowing those who wish to upgrade to store the type as e.g. "array$_User", where the $ would signal a bifurcation in the SchemaController.

This migration could be sped up using a simple code snippet that runs through an active database (at runtime), and updates the _Schema class with extracted array pointer classes where available.

@davimacedo

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

We could also leave the Array data type as it is now (to avoid the breaking change or any migration) and just add a metadata specifying it is a pointer Array (like we did in the required fields). What do you think? Is this something that you would be willed to tackle?

@Moumouls

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

We could also have a huge problem with multi pointers in an Array (ex: [User, Role, Product]).

I think the solution is to implement an InlineFragment strategy: GraphQL InlineFragment

Tasks:

  • Create an Union Type: ArrayResult, add all Classes to the UnionType and a ScalarObjectType: Implement Union Type
  • Add doc on the field about the InlineFragment strategy
  • Implement the InlineFragment on Array Resolvers

Example:

query JobQuery {
  objects {
    getJob(objectId: "sqvJTrN9no") {
      title
      company {
        name
      }
      countries {
        ... on Country {
          name
        }
      }
    }
}

Multi Pointer example:

query JobQuery {
  objects {
    getJob(objectId: "sqvJTrN9no") {
      title
      company {
        name
      }
      relatedTo {
        ... on Country {
          name
          objectId
        }
        ... on ProfessionalCode {
          readableName
          code
          objectId
        }
      }
    }
}
@Moumouls Moumouls referenced this issue Aug 12, 2019
3 of 3 tasks complete
@davimacedo

This comment has been minimized.

Copy link
Member

commented Aug 12, 2019

@Moumouls thanks for the suggestion. I think it is really the best way to solve this issue! I will take a look in your PR and revert my feedback.

@davimacedo davimacedo closed this Aug 14, 2019

@Moumouls

This comment has been minimized.

Copy link
Member

commented Aug 14, 2019

@murshudov on the master branch you can test the new powerful InlineFragment feature, example here:

Query

{
  objects {
    getCountry(objectId: "8dDDVCHN2q") {
      objectId
      name
      companies {
        ... on CompanyClass {
          objectId
          name
          employees {
            ... on EmployeeClass {
              objectId
              name
            }
          }
          teams {
            ... on TeamClass {
              objectId
              name
              employees {
                ... on EmployeeClass {
                  objectId
                  name
                  country {
                    objectId
                    name
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Response

{
  "data": {
    "objects": {
      "getCountry": {
        "objectId": "8dDDVCHN2q",
        "name": "imACountry",
        "companies": [
          {
            "objectId": "jk2pZjsDsv",
            "name": "imACompany",
            "employees": [
              {
                "objectId": "7KBQ8bOpZA",
                "name": "imAnEmployee"
              }
            ],
            "teams": [
              {
                "objectId": "dRiSUajdpq",
                "name": "imATeam",
                "employees": [
                  {
                    "objectId": "7KBQ8bOpZA",
                    "name": "imAnEmployee",
                    "country": {
                      "objectId": "8dDDVCHN2q",
                      "name": "imACountry"
                    }
                  }
                ]
              }
            ]
          }
        ]
      }
    }
  }
}

Don't be afraid of performance when diving into objects, this example was executed in 17ms (macbook pro i7 15" 2016), with only one call REST Parse Server.

@murshudov

This comment has been minimized.

Copy link
Author

commented Aug 15, 2019

@Moumouls and others, thank you very much for the great effort and awesome work 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.