Skip to main content
Solved

Pagination using "hasMore" response

  • August 26, 2024
  • 9 replies
  • 146 views

I am dealing with an API that let’s me query its database. With LIMIT and OFFSET I want to fetch all the rows dynamically using an RSD file.

Here’s the json response:

{
    "entities": [
        {
            "Portfolio": {
                "id": "9999999999999999",
                "Name": "Test9"
            }
        },
        {
            "Portfolio": {
                "id": "1111111111111111",
                "Name": "Test1"
            }
        }
    ],
    "paging": {
        "from": 2,
        "hasMore": true,
        "limit": 2
    }
}

And here is my RSD file. I haven’t gotten it to work with pagination and I just get the error

The attribute 'hasMore' does not exist.

<api:script xmlns:api="http://apiscript.com/ns?v1" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- See Column Definitions to specify column behavior and use XPaths to extract column values from JSON. -->
  <api:info title="entities" desc="Generated schema file_" xmlns:other="http://apiscript_com/ns?v1"> />
	<attr name="portfolio_id"                                  	xs:type="string"   readonly="false"              other:xPath="/json/entities/Portfolio/id"                                  />
    <attr name="portfolio_name"                                	xs:type="string"   readonly="false"              other:xPath="/json/entities/Portfolio/Name"                                />
	<input name="rows@next" default="0" />
  </api:info>

  <api:set attr="DataModel" value="FLATTENEDDOCUMENTS" />
  <api:set attr="BASEURI" value="https://apie1.clarizen.com/V2.0/services/data/query" />

  <api:set attr="ElementMapPath#" value="/json/paging/hasMore" />
  <api:set attr="ElementMapName#" value="hasMore" />
  <api:set attr="EnablePaging" value="TRUE" />

  <api:script method="GET">
	<api:set attr="AddToURI" value="q=SELECT+Portfolio.Name+FROM+Portfolio+LIMIT+2+OFFSET+[_input.rows@next]"/>
	<api:set attr="URI" value="[BaseURI]?[AddToURI]" />
	<api:set attr="method" value="GET"/>
    <api:call op="jsonproviderGet">
		<api:if attr="hasMore" value="true" operator="equals">
			<api:set attr="rows@next" value="[rows@next | Add(2)]" />
		</api:if>
      <api:push/>
    </api:call>
  </api:script>

</api:script>

 

If I’d script this in Python I’d just have a while hasMore=’true’ THEN continue. But I’m unsure how to do this with an RSD file.

Best answer by Gardar

@Thomas Lind, thanks for the suggestions! It worked with the following:

<api:set attr="JSONPath" value="$.entities;$." />

I thought that by setting JSONPath to “.$” it would include all subcategories as well. If I set it to only “$.entities” it would not find the hasMore attribute. Setting it to the above returns all rows as they should be.

View original
Did this topic help you find an answer to your question?

9 replies

Thomas Lind
Community Manager
Forum|alt.badge.img+5
  • Community Manager
  • 1015 replies
  • August 28, 2024

Hi @Gardar 

If you hit the last page where the hasMore is False, what is the pagination result looking like?

Also do you have the Row Scan Depth set to 0?


  • Author
  • Contributor
  • 7 replies
  • August 29, 2024

Hi @Thomas Lind,

The pagination when using LIMIT 2 OFFSET 1615 reaches the end of the list with this pagination result:

"paging": {
        "from": 1616,
        "limit": 2,
        "hasMore": false
    }

I did not have row scan depth set to 0 as the query should only return 2 rows (+ paging result). I now tried to set it to 0 but I get the same error:

The attribute 'hasMore' does not exist.


  • Contributor
  • 75 replies
  • August 29, 2024

I may be missing something obvious but is the element mapping really necessary? For basic pagination it should be enough to just add the hasMore field like this:

<attr name="hasMore" xs:type="xs:boolean" readonly="false" other:xPath="/json/paging/hasMore" />

And you may need this:

<api:set attr="Repeatelement" value="/json/entities" />

Can you verify that you are actually getting one page with a result (I expected some kind of authentication first).

 

 


  • Author
  • Contributor
  • 7 replies
  • August 29, 2024

@RLB Thank you for the answer. The problem I have is that I need to pass in a LIMIT and OFFSET into the API request. I assume that this type of “Repeatelement” approach would work under normal circumstances. If I do as you have said, I will only get 2 rows as the attribute [AddToURI] is not changing.


Thomas Lind
Community Manager
Forum|alt.badge.img+5
  • Community Manager
  • 1015 replies
  • August 29, 2024

Hi @Gardar 

Try this setup.

<api:script xmlns:api="http://apiscript.com/ns?v1" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- See Column Definitions to specify column behavior and use XPaths to extract column values from JSON. -->
  <api:info title="entities" desc="Generated schema file_" xmlns:other="http://apiscript_com/ns?v1"> />
	<attr name="portfolio_id"                                  	xs:type="string"   readonly="false"              other:xPath="/json/entities/Portfolio/id"                                  />
    <attr name="portfolio_name"                                	xs:type="string"   readonly="false"              other:xPath="/json/entities/Portfolio/Name"                                />
	<input name="rows@next" default="0" />
  </api:info>

  <api:set attr="DataModel" value="FLATTENEDDOCUMENTS" />
  <api:set attr="BASEURI" value="https://apie1.clarizen.com/V2.0/services/data/query" />
  <api:set attr="JSONPath" value="$.entities.Portfolio" />
  <api:set attr="ElementMapPath#" value="/json/paging/hasMore" />
  <api:set attr="ElementMapName#" value="hasMore" />
  <api:set attr="EnablePaging" value="TRUE" />

  <api:script method="GET">
	<api:set attr="AddToURI" value="q=SELECT+Portfolio.Name+FROM+Portfolio+LIMIT+2+OFFSET+[_input.rows@next]"/>
	<api:set attr="URI" value="[BaseURI]?[AddToURI]" />
	<api:set attr="method" value="GET"/>
    <api:call op="jsonproviderGet">
		<api:if attr="hasMore" value="true" operator="equals">
			<api:set attr="rows@next" value="[rows@next | Add(2)]" />
		</api:if>
      <api:push/>
    </api:call>
  </api:script>

</api:script>

What I did was to add a JSONPAth field to point at the data. This may be part of the issue, also consider changing the DataModel to just DOCUMENTS.


  • Author
  • Contributor
  • 7 replies
  • August 29, 2024

Thanks @Thomas Lind. I tried your suggestion but the error stayed the same. I changed the JSONPath to:

<api:set attr="JSONPath" value="$." />
And it seems to work “somewhat” now. I changed it to LIMIT 1000 and 
[rows@next | Add(1000)]

As there are >1600 rows to fetch, I see in the log_file (with verbosity = 5) that it is doing the correct thing:

GET https://apie1.clarizen.com/V2.0/services/data/query?q=SELECT+Portfolio.Name+FROM+Portfolio+LIMIT+1000+OFFSET+0

followed by:

GET https://apie1.clarizen.com/V2.0/services/data/query?q=SELECT+Portfolio.Name+FROM+Portfolio+LIMIT+1000+OFFSET+1000

And I see in the buffer log that it is fetching all the data.

 

But it seems that it only returns the first row of each query. Selecting from the portfolio table in TimeXtender returns only 2 rows.


Thomas Lind
Community Manager
Forum|alt.badge.img+5
  • Community Manager
  • 1015 replies
  • August 29, 2024

Hi @Gardar 

It likely still is the JSONPath that is the issue.

$. is the highest level it may not return more than one row. See if you can try other options like $.entities and similar


  • Author
  • Contributor
  • 7 replies
  • Answer
  • August 29, 2024

@Thomas Lind, thanks for the suggestions! It worked with the following:

<api:set attr="JSONPath" value="$.entities;$." />

I thought that by setting JSONPath to “.$” it would include all subcategories as well. If I set it to only “$.entities” it would not find the hasMore attribute. Setting it to the above returns all rows as they should be.


Thomas Lind
Community Manager
Forum|alt.badge.img+5
  • Community Manager
  • 1015 replies
  • August 30, 2024

Hi @Gardar 

When you use FlattenedDocuments as the DataModel adding multiple options in the JSONPath field is normally what is expected. So using ; between statements pulls all together in one file.


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings