Re: GraphQL: Query nested pagination for OrderAgreement -> Sales

GraphQL: Query nested pagination for OrderAgreement -> Sales

Timbersson
Shopify Partner
4 0 1

Hi,

 

I'm trying to query order agreements using the GraphQL admin API, but I'm stuck on how to retrieve additonal pages for the nested "sales" connection within each agreement My  initial query to get the agreements, with extraneous fields stripped out, looks something like the following - the section in bold is the nested connection that I need to be able to query for more pages :

 

query getOrder($id: ID!) {
  order(id: $id) {
    agreements(first: 2) {
      edges {
        node {
          id
          happenedAt
          sales(first: 5) {
            edges {
              node {
                lineType
                actionType
              }
            }
            pageInfo {
              hasNextPage
              endCursor
            }
          }
        }
        cursor
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

 

Where the outer pagination indicates that there are more agreements to retrieve I can use a similar query, passing in a cursor to get the next page of agreements:

query getMoreAgreements($id: ID!, $cursor: String) {
  order(id: $id) {
    agreements(first: 5, after: $cursor) {
        ... <snip>
    }
  }
}

 

What I can't figure out is a way that I can query for a specific OrderAgreement in order that I can then use the appropriate cursor to get the next page of "Sale"s for that agreement. 

 

Could anyone suggest how to achieve this? 

 

Thanks,

Tim

Replies 8 (8)

ShopifyDevSup
Shopify Staff
1453 238 509

Hi @Timbersson 👋

 

You should be able to pass the cursor at the root and paginate the nested sales nodes as shown below. The `$c` variable should reflect the `endCursor` on the `firstSale` alias.

 

query ($id: ID!, $c: String!){
    order (id: $id) {
        agreements (first: 1) {
            nodes {
                id
                firstSale: sales (first: 1) {
                    nodes {
                        id
                    }
                    pageInfo {
                        endCursor #suppose this is "abc123="
                        hasNextPage
                    }
                }
                secondSale: sales (first: 1, after: $c) {
                    nodes {
                        id
                    }
                }
            }
        }
    }
}

With variables: 

{
    "id":"gid://shopify/Order/123456",
    "c":"abc123="
}

 

Hope that helps!

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Timbersson
Shopify Partner
4 0 1

Hey @ShopifyDevSup ,

 

Thanks for the reply, however in my tests that seems to only work for the first agreement in a particular order. Passing in a sales cursor from a subsequent agreement results in an empty list of edges under sales.  

 

To illustrate - lets say I have an order with 2 agreements, and 2 sales nested under each agreement:

 

"id": "gid://shopify/SalesAgreement/1"
  "id": "gid://shopify/Sale/10",
  "id": "gid://shopify/Sale/11",


id": "gid://shopify/SalesAgreement/2",
  "id": "gid://shopify/Sale/12",
  "id": "gid://shopify/Sale/13",

 

 I can query the agreements in in the order, getting the first sale for each agreement something like this:

 

query firstSales($id: ID!){
  order (id: $id) {
    agreements (first: 5) {
      edges {
        node {
          id
          sales (first: 1) {
            edges { node { id  } }
            pageInfo { hasNextPage endCursor }
          }
        }
      }
    }
  }
}

 

 

 For the hypothetical order above, I get back a response as follows:

 

"order": {
  "agreements": {
    "edges": [
      { 
	    "node": {
          "id": "gid://shopify/SalesAgreement/1",
          "sales": {
            "edges": [{ "node": {"id": "gid://shopify/Sale/10"}}],
            "pageInfo": { "hasNextPage": true, "endCursor": "abc123" }
          }
        }
      },
      {
        "node": {
          "id": "gid://shopify/SalesAgreement/2",
          "sales": {
            "edges": [{"node": {"id": "gid://shopify/Sale/12"}}],
            "pageInfo": {"hasNextPage": true, "endCursor": "def456"}}
        }
      }
    ]
  }
}

 

 So far so good. If I use a query similar to the one suggested, passing in the cursor "abc123"  to the sales connection then all is well: I recieve a response that contains information for "gid://shopify/Sale/11".

 

The problem comes when I pass in cursor "def456" - in this case I get an empty list of  sale edges. It seems that the (first:1) on the agreements connection always selects the first agreement, regardless of the cursor that is used further down the query.

Timbersson
Shopify Partner
4 0 1

Ok, so having experimented with this a little more I have found a kind of work-around solution, though it does not feel very elegant - you need to manage two separate cursors: one to select the agreement, the another for the Sales connection.

 

The initial query to get the agreements and first sales for each also gets a cursor for each agreement:

query firstSales($id: ID!){
  order (id: $id) {
    agreements (first: 5) {
      edges {
        cursor
        node {
          id
          sales (first: 1) {
            edges { node { id  } }
            pageInfo { hasNextPage endCursor }
          }
        }
      }
    }
  }
}

 

Resulting in something like this:

"order": {
  "agreements": {
    "edges": [
      { 
	    "cursor": "agreement_cursor_1",
	    "node": {
          "id": "gid://shopify/SalesAgreement/1",
          "sales": {
            "edges": [{ "node": {"id": "gid://shopify/Sale/10"}}],
            "pageInfo": { "hasNextPage": true, "endCursor": "abc123" }
          }
        }
      },
      {
	    "cursor": "agreement_cursor_2",
        "node": {
          "id": "gid://shopify/SalesAgreement/2",
          "sales": {
            "edges": [{"node": {"id": "gid://shopify/Sale/12"}}],
            "pageInfo": {"hasNextPage": true, "endCursor": "def456"}}
        }
      }
    ]
  }
}

 

You can then then pass the cursor of the previous agreement to the one for which you need to read more sales, to a query like this:

query moreSales($id: ID!, $cursor_sale: String!, $cursor_prev_agreement: String){
  order (id: $id) {
    agreements (first: 1, after:$cursor_prev_agreement) {
      edges {
        node {
          sales (first: 1, after: $cursor_sale) {
            edges {
              node { id }
            }
          }
        }
      }
    }
  }
}

 

Calling this query with variables as follows will return the second sale for the second agreement.

{
	"id": "order_id",
	"cursor_sale": "def456",
	"cursor_prev_agreement": "order_agreement_1"
}

 

It works, but it doesn't smell good 🙁

 

@ShopifyDevSup is there any chance that SaleAgreement can / will be made to implement "Node" so that they could be queried using the global "node" query? This would allow a much more elegant solution to this problem than the one I've suggested here.

 

Thanks,

Tim

 

 

 

 

 

ShopifyDevSup
Shopify Staff
1453 238 509

Absolutely, `SaleAgreement` would definitely be better implemented to extend a `node` interface. Really appreciate you finding a work-around for now, and I'll be sure to share this with the product team!


If you're looking to fetch the universe of `SaleAgreement` nodes, a bulk query may be an option as well:

 

mutation {
    bulkOperationRunQuery(query: "{ orders { edges { node { id agreements { edges { node { id sales { edges { node { id } } } } } } } } } }") {
        bulkOperation {
            id
            status
        }
    }
}

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

ClementBR
Shopify Partner
161 2 48

We're running into the same issues.

Thanks for sharing the work around.

 

@ShopifyDevSup there are has been multiple API release since then an neither SaleAgreement or Sale extend the node interface yet.

 

ShopifyDevSup
Shopify Staff
1453 238 509

Hey @ClementBR , I've taken a look here and I can see that the feedback is currently still submitted with the product team. I don't have an estimate at this time though if this is currently in the roadmap. 

 

I'd be happy to pass on additional feedback if you're able to share a little more information on specifically how this will be beneficial for you beyond what has already been shared. More context is always helpful. 

Thanks, 

- Kyle G. 

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

ClementBR
Shopify Partner
161 2 48

@ShopifyDevSup 

It would make the pagination issue described above much cleaner and easier.

 

The work around suggested above by  @Timbersson  works but it is very convoluted and very inefficient.

It requires keeping track of the previous agreement in the list and then paginating each agreement's sales with a separate query for each agreement

 

If Agreement implemented the node interface, then we could simply issue a nodes query to paginate multiple agreements' sales with a single query, and without needing to keep track of the previous cursor in the list.

 

 

If 

ShopifyDevSup
Shopify Staff
1453 238 509

Hey @ClementBR , thanks for sharing that. I have passed that additional feedback on for you! 

 

Have a great weekend. 

 

- Kyle G.

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog