{"id":277,"date":"2010-05-28T22:59:18","date_gmt":"2010-05-28T17:29:18","guid":{"rendered":"http:\/\/naveenbalani.com\/?p=277"},"modified":"2017-03-24T18:05:45","modified_gmt":"2017-03-24T12:35:45","slug":"approach-to-handle-pagination-in-dynamic-pages","status":"publish","type":"post","link":"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/","title":{"rendered":"Approach to handle pagination in dynamic pages"},"content":{"rendered":"<p>Many Web-based applications include the requirement to display some part of the user search results in chunks of pages. For example, think of the typical search engine, say Google, which displays search results in chunks of 10 or more items per page.<\/p>\n<p>In this blog, I will describe how to implement this design requirement using features provided by DB2 \u00c2\u00ae Universal Database TM (UDB) and how to cache the results using a stateful bean or session. Though this example is specific to DB2 and JSP, the same approach can be used with any relational database and dynamic pages technique.<\/p>\n<p>We will consider two approaches:<\/p>\n<p>* Querying the database to get records in chunks using the rownext() feature of DB2<br \/>\n* Caching results in stateful session beans or HttpSession<\/p>\n<p><strong>The scenario<\/strong><\/p>\n<p>We shall consider these approaches by looking at a scenario for a product-based Web site which allows the user to search for products offered based on category, price, brand, and so on. The results will be displayed in chunks of user-defined page sizes, say 10 or 20 items.<\/p>\n<p>Here are our sample table definitions:<\/p>\n<pre>\r\nCREATE TABLE Product_Category(\r\ncategory_id integer not null,\r\ncategory_name varchar(200), not null\r\ncategory_decription varchar2(500)\r\n)\r\n\r\nCREATE TABLE Product (\r\nproduct_id Integer not null,\r\nproduct_name varchar2(50) not null,\r\nprod_category_id integer not null,\r\nproduct_decription varchar2(100) not null,\r\nproduct_price decimal(15,2),\r\nproduct_status char(1) default 'Y',\r\nproduct_width decimal(5,2) not null,\r\nproduct_length decimal(5,2) not null,\r\nproduct_created_date  timestamp,\r\nproduct_netweight  decimal(10,3),\r\nconstraint PK_PRODUCT_ID PRIMARY KEY\r\n(product_id),\r\nconstraint product_category_fk foreign key\r\n(prod_category_id)\r\nreferences Product_Category (category_id))\r\n<\/pre>\n<p><strong>Using DB2 features to achieve pagination<\/strong><\/p>\n<p>This approach is good for applications where you have a chance to do some design work before the database and application go into production.<\/p>\n<p>Here we assume that the user wants the products to be displayed in chunk of 20 results per page. As we know, the rows in a relational table have no specific order, so the SQL query needs to be designed to allow the data to be retrieved in a particular order using an ORDER BY clause on the primary key, which in our case is our product id.<\/p>\n<p>DB2 allows you to order a result set on the fly and fetch an arbitrary number of rows from the beginning or end of this result set.<\/p>\n<p>Here is a query to select first 20 records from our product table based on the category &#8220;Books.&#8221;<\/p>\n<pre>\r\nSELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESCRIPTION,\r\nPRODUCT_PRICE, PROD_CATEGORY_ID\r\nFROM PRODUCT,PRODUCT_CATEGORY\r\nWHERE\r\nPRODUCT.PROD_CATEGORY_ID\r\n= PRODUCT_CATEGORY.CATEGORY_ID\r\nAND\r\nPRODUCT_CATEGORY.CATEGORY_ID = 'Books'\r\nORDER BY PRODUCT.PRODUCT_ID\r\nFETCH FIRST 20 ROWS ONLY\r\n<\/pre>\n<p>The ORDER BY will force a sort of the entire result set in memory, so we&#8217;re not doing this to improve DB2 server performance (although sending only 10 rows to the client may improve network performance).<!--more--><\/p>\n<p>If the order is not a factor and we just want to get the first 20 rows based on the user criteria, then we can eliminate the ORDER BY to save the sort on the DB2 server:<\/p>\n<pre>\r\nSELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESCRIPTION,\r\nPRODUCT_PRICE, PROD_CATEGORY_ID\r\nFROM PRODUCT,PRODUCT_CATEGORY\r\nWHERE\r\nPRODUCT. PROD_CATEGORY_ID\r\n= PRODUCT_CATEGORY.CATEGORY_ID\r\nAND\r\nPRODUCT_CATEGORY.CATEGORY_ID = 'Books'\r\nFETCH FIRST 20 ROWS ONLY\r\n<\/pre>\n<p>Since the application needs to display say 20 results per page, we can make use of the row_next() feature provided by DB2.<\/p>\n<p>Below is an example of how to select results from rows numbered 21 to 40. We assume that the user has selected category as &#8220;Books&#8221; and product description as &#8220;Application Servers&#8221;.<\/p>\n<pre>SELECT * FROM (\r\nSELECT PRODUCT_ID, PRODUCT_NAME,\r\nPRODUCT_DESCRIPTION, PRODUCT_PRICE,\r\nrownumber() OVER\r\n(ORDER BY PRODUCT_ID)\r\nAS ROW_NEXT\r\nFROM PRODUCT,PRODUCT_CATEGORY WHERE\r\nPRODUCT.PROD_CATEGORY_ID\r\n= PRODUCT_CATEGORY.CATEGORY_ID\r\nAND\r\nPRODUCT_CATEGORY.CATEGORY_ID = 'Books'\r\nAND\r\nPRODUCT.PRODUCT_DESCRIPTION LIKE\r\n'Application Servers'\r\n)\r\nAS PRODUCT_TEMP WHERE\r\nROW_NEXT BETWEEN 21 and 40\r\n<\/pre>\n<p>In the case of a Web-based application, the parameters &#8220;21&#8221; and &#8220;40&#8221; can be specified at run time. Here is the modified query:<\/p>\n<pre>SELECT * FROM (\r\nSELECT PRODUCT_ID, PRODUCT_NAME,\r\nPRODUCT_DESCRIPTION, PRODUCT_PRICE,\r\nrownumber() OVER\r\n(ORDER BY PRODUCT_ID) AS ROW_NEXT\r\nFROM PRODUCT,PRODUCT_CATEGORY\r\nWHERE\r\nPRODUCT. PROD_CATEGORY_ID\r\n= PRODUCT_CATEGORY.CATEGORY_ID\r\nAND\r\nPRODUCT_CATEGORY.CATEGORY_ID = 'Books'\r\nAND\r\nPRODUCT. PRODUCT_DESCRIPTION LIKE\r\n'Application Servers'\r\n)\r\nAS PRODUCT_TEMP WHERE\r\nROW_NEXT BETWEEN ? and ?\r\n<\/pre>\n<p>The rownumber() function allows the developers to assign row numbers to results sets on the fly.<\/p>\n<p>If the row_next clause is removed ( ROW_NEXT BETWEEN ? and ? ), all the rows that matched the criteria will be returned.<\/p>\n<p>The SELECT * FROM clause in case above can be thought of as a temporary table holding the entire result set that matches the criteria and than returning that set of results specified in the row range.<\/p>\n<p>Using the rownumber() feature will cause an additional performance impact on the system as the database first fetches all rows that matches the criteria and returns only those rows specified in the range.<\/p>\n<p>Next we look at the trade-offs and advantages of this approach and when it&#8217;s an appropriate choice.<\/p>\n<p>Trade-offs for this approach<\/p>\n<ul>\n<li>Transactions and performance impact<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\">In this approach, the transactions need to be handled programmatically by the developer. In our scenario, if we assume that products are updated only once daily, say at midnight, we can use the lowest transaction isolation level of READ_UNCOMITTED.<\/p>\n<p style=\"padding-left: 30px;\">Using the row_next feature definitely will have some performance impact on the database application as compared to a query without the row_next feature. Also this approach requires us to hit the database each time to get next sequence of result sets based on the range of rows.<\/p>\n<ul>\n<li>Code portability<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\">Fetching an arbitrary number of rows from the beginning or end of this result set is provided by almost every RDBMS system, though the SQL syntax varies. Hence if we move from one database vendor to other, we might have to modify the query accordingly.<\/p>\n<ul>\n<li>Providing seamless back button functionality<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\">If our design requires browser back button functionality and the user is interested in viewing the latest information from the database each time, then this design can provide a possible solution. The drawback is that this may require a hit on the database for each results page, which might affect the performance drastically.<\/p>\n<p style=\"padding-left: 30px;\">Basically the URL query will have the search parameters embedded which can be fed to our SQL Query. Here is a possible URL query:<br \/>\nhttp:\/\/localhost:8050\/ProductSearch?<br \/>\nminprize=50&amp; maxprice=100&amp; pagecount=20&amp; resultsPerpage=10<\/p>\n<p style=\"padding-left: 30px;\">When the user clicks on browser back button, the previous URL to be displayed in browser will be:<\/p>\n<p style=\"padding-left: 30px;\">http:\/\/localhost:8050\/ProductSearch?<br \/>\nminprize=50&amp;maxprice=100&amp;pagecount=10&amp;resultsPerpage=10<\/p>\n<p style=\"padding-left: 30px;\">We&#8217;ll assume that the latest page id is available in the session. So the browser back button can be tracked as follows:<\/p>\n<pre>if(!session.getAttribute(\"pageID).equalsIgnoreCase\r\n(request.getAttribute(\"pageCount\")){\r\n\/\/Then user has clicked the back button\r\n\/\/Get possible search parameters, pagecount\r\n\/\/and resultsPerPage from URL and formulate\r\n\/\/a dynamic URL and post the information back\r\n\/\/to the servlet.The URL would be\r\nhttp:\/\/localhost:8050\/ProductSearch?minprize=50&amp;amp;\r\nmaxprice=100&amp;amp;amp;pagecount=10&amp;amp;amp;resultsPerpage=10&amp;lt;\/p&amp;gt;\r\nreturn;\r\n\/\/Done display the results screen page\r\n}<\/pre>\n<p style=\"padding-left: 30px;\">Using this approach the user will be able to view the latest information from the database.<\/p>\n<p>Next we move on to our second approach, which is widely used in many applications.<\/p>\n<p><strong>Caching result sets in stateful beans or HttpSession<\/strong><\/p>\n<p>This is one of the widely used approaches to pagination in which results are cached in some stateful object like session beans or HttpSession. The choice between HttpSession or stateful bean depends upon the size of the data to be retrieved. If there is large amount of data one should definitely go for the stateful session bean method.<\/p>\n<p>In this approach we would get all the results from the database in one go and store the results in our stateful session bean.<\/p>\n<p>Here is a possible query to retrieve all the books that are available in our product table:<\/p>\n<pre>[\r\n\r\nSELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESCRIPTION,\r\nPRODUCT_PRICE, PROD_CATEGORY_ID\r\nFROM PRODUCT\r\nWHERE\r\nPRODUCT. PROD_CATEGORY_ID\r\n= PRODUCT_CATEGORY.CATEGORY_ID\r\nAND\r\nPRODUCT_CATEGORY.CATEGORY_ID = 'Books'\r\n<\/pre>\n<p>Here is our design of our remote interface stateful bean:<\/p>\n<pre>\r\npublic void setSearchResults(Category category)\r\nthrows RemoteException\r\n\r\npublic Category getPerPagSearchResults(String page_count)\r\nthrows RemoteException\r\n\r\nHere is what typical Category and Product objects would look like:\r\n\r\npublic class Category extends java.io.Serializable {\r\nprivate String category_id,\r\nprivate String category_name,\r\n\/\/Holds an Array List of products under that category.\r\nprivate ArrayList products;\r\n}\r\n\r\npublic class Product extends java.io.Serializable {\r\nprivate String product_id;\r\nprivate String product_name;\r\nprivate String product_desc;\r\nprivate String product_price;\r\n}\r\n<\/pre>\n<p>Here are the steps required to achieve pagination:<\/p>\n<p>1. Get the result set based on the search criteria.<br \/>\n2. Loop though the result set and store each product object in our product ArrayList.<br \/>\n3. Store the array list of project objects in the category object.<br \/>\n4. Call our remote method setSearchResults and store the category object.<br \/>\n5. In order to get results to be displayed per page, call the remote method getPerPagSearchResults() passing the page_count (such as 10 or 20) to retrieve the corresponding records.<\/p>\n<p>Here is our typical implementation of getPerPagSearchResults(String page_count):<\/p>\n<pre>\r\n\/\/Check if Product List contains at least page_count products\r\nint len = category.getProduct_list().length&amp;amp;gt;page_count\r\n? page_count : category.getProduct_list().length\r\n\r\nArrayList product_tempList  = new ArrayList();\r\n\r\nfor( int i = page_count+1 ; i &amp;amp;lt; len ; i++){\r\n\/\/Loop though the product list array and get\r\n\/\/corresponding records\r\nproduct_tempList.add(category.getProduct_list().get(I);\r\n}\r\n\r\n\/\/return category object containing an arraylist of\r\n\/\/products containg records from page_count\r\n\/\/to page_count+10 or product_list.length if\r\n\/\/product_list.length is less than page_count+10\r\n\r\nreturn product_tempList\r\n<\/pre>\n<p>The product list can be iterated and all the product information can be displayed at that point. Whenever the next button is clicked the next page_count can be passed to our servlet, which does the same process listed above.<\/p>\n<p>Trade-offs for this approach<\/p>\n<ul>\n<li>Transaction and performance impact<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\">In this approach, fetching the result set based on the search criteria needs to be handled by the developer, while maintaining the state of our category object to implement caching is handled by the EJB Container. This provides an additional layer for managing our client state.<\/p>\n<p style=\"padding-left: 30px;\">This approach will definitely provide better performance than our earlier one, as we will avoid subsequent database calls and will have caching of result sets.<\/p>\n<p style=\"padding-left: 30px;\">Since we are caching the results, it is possible that the user might be viewing stale data. Because of this issue, this approach is well-suited for an application where the data is not constantly updated. For example if you are updating your products list every night at midnight, then the viewer will likely not be viewing stale data when using the application throughout the day.<\/p>\n<ul>\n<li>Code portability<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\">This approach provides a vendor-neutral approach as our caching logic can be moved from one EJB container to another without changing our code. However we might have to modify our EJB vendor-specfic deployment descriptor if the code needs to be run on different EJB containers.<\/p>\n<ul>\n<li>Providing back button functionality using this approach<\/li>\n<\/ul>\n<p style=\"padding-left: 30px;\">Consider an example where the browser cache is disabled and the user clicks on the browser back button. That would result in the browser requesting the JSP page again. Now suppose we navigate across different search criteria pages. As per this design only the latest search results will be displayed, as we are keeping our latest search results in the Stateful bean. So in order to track which search criteria the user is working on, we can store the search criteria in the session and compare it with request parameters present in the URL when user clicks on the browser back button.<\/p>\n<p style=\"padding-left: 30px;\">Here is sample code that is present in the JSP which displays Search Results page:<\/p>\n<p style=\"padding-left: 30px;\">SearchCriteria searchObjSession = (SearchCriteria)<br \/>\nsession.getAttribute(&#8220;SearchCriteria&#8221;)<\/p>\n<p style=\"padding-left: 30px;\">Next we would get search parameters from the URL .Here we assume that URL is:<\/p>\n<p style=\"padding-left: 30px;\">http:\/\/localhost:8050\/ProductSearch?minprize=50&amp;maxprice=100<br \/>\n&amp;pagecount=10&amp;resultsPerpage=10<\/p>\n<p style=\"padding-left: 30px;\">Here is the sample code:<\/p>\n<pre>\r\nSearchCriteria  previousSearch = new SearchCriteria();\r\nIf(request.getAttribute(\"minPrice\") != null){\r\npreviousSearch.setMinPrice(request.getAttribute(\"minPrice\"))&amp;lt;\/p&amp;gt;\r\n\/\/and so on for remaining parameters\r\n\/\/Next we would compare our SearchCriteria object from session with our PreviousSearch object:\r\nif(!searchObjSession.equals(previousSearch)){\r\n\/\/User is trying to view previous search results\r\n\/\/Show an error to user that he is allowed to work on latest\r\n\/\/search criteria only or else\r\n\/\/depending on your business logic you can give a call to\r\n\/\/database with previous search\r\n\/\/criteria and store it in our Stateful bean and display the\r\n\/\/results back to the user.\r\n\/\/Redirect him to Search Criteria Page or Search Results Page\r\n\/\/ return;\r\n}<\/pre>\n<p><strong>Which approach is best for me?<\/strong><\/p>\n<p>Based on your requirements you can apply a combination of both approaches. The most widely used approach is that which provides caching of result sets.<\/p>\n<p>Consider a scenario where we want to display only the latest 20 products that have been added. The first approach definitely can be used since in this case sorting of the result sets and providing only 20 records would be a job for the database system. This scenario is very useful if your database is located remotely as this will ensure only 20 records flow over the network layer.<\/p>\n<p><strong>Conclusion<\/strong><\/p>\n<p>We&#8217;ve talked about how to achieve pagination using two possible approaches. Depending upon your application and business needs, one of these approaches can be used to solve the pagination problem for your Web applications.<\/p>\n<p>This article of mine was first published by IBM DeveloperWorks at -http:\/\/www.ibm.com\/developerworks\/data\/library\/techarticle\/0307balani\/0307balani.html.All rights retained by IBM and the author.<br \/>\n<noscript>&amp;amp;amp;amp;lt;A HREF=&#8221;http:\/\/ws.amazon.com\/widgets\/q?ServiceVersion=20070822&amp;amp;amp;amp;amp;MarketPlace=US&amp;amp;amp;amp;amp;ID=V20070822%2FUS%2Fsw0fd-20%2F8003%2F34b0bfca-73fa-4e85-be5a-01e2b6e00b80&amp;amp;amp;amp;amp;Operation=NoScript&#8221; mce_HREF=&#8221;http:\/\/ws.amazon.com\/widgets\/q?ServiceVersion=20070822&amp;amp;amp;amp;amp;amp;MarketPlace=US&amp;amp;amp;amp;amp;amp;ID=V20070822%2FUS%2Fsw0fd-20%2F8003%2F34b0bfca-73fa-4e85-be5a-01e2b6e00b80&amp;amp;amp;amp;amp;amp;Operation=NoScript&#8221;&amp;amp;amp;amp;gt;Amazon.com Widgets&amp;amp;amp;amp;lt;\/A&amp;amp;amp;amp;gt;<\/noscript><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Many Web-based applications include the requirement to display some part of the user search results in chunks of pages. For example, think of the typical search engine, say Google, which displays search results in chunks of 10 or more items per page. In this blog, I will describe how to implement this design requirement using [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2128,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[66,3],"tags":[28,67],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v16.0.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Approach to handle pagination in dynamic pages - Current and Future Technology Trends by Navveen Balani<\/title>\n<meta name=\"description\" content=\"Approach to handle pagination in dynamic pages -\" \/>\n<link rel=\"canonical\" href=\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Approach to handle pagination in dynamic pages - Current and Future Technology Trends by Navveen Balani\" \/>\n<meta property=\"og:description\" content=\"Approach to handle pagination in dynamic pages -\" \/>\n<meta property=\"og:url\" content=\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/\" \/>\n<meta property=\"og:site_name\" content=\"Current and Future Technology Trends by Navveen Balani\" \/>\n<meta property=\"article:published_time\" content=\"2010-05-28T17:29:18+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-03-24T12:35:45+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/navveenbalani.dev\/wp-content\/uploads\/2016\/09\/bk6.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"450\" \/>\n\t<meta property=\"og:image:height\" content=\"374\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\">\n\t<meta name=\"twitter:data1\" content=\"12 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/navveenbalani.dev\/#website\",\"url\":\"https:\/\/navveenbalani.dev\/\",\"name\":\"Current and Future Technology Trends by Navveen Balani\",\"description\":\"Current and Future Technology Trends by Navveen Balani\",\"publisher\":{\"@id\":\"https:\/\/navveenbalani.dev\/#\/schema\/person\/51f7ab14b20611d95e3c7fd4ea0950bf\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/navveenbalani.dev\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/navveenbalani.dev\/wp-content\/uploads\/2016\/09\/bk6.jpg\",\"width\":450,\"height\":374},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#webpage\",\"url\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/\",\"name\":\"Approach to handle pagination in dynamic pages - Current and Future Technology Trends by Navveen Balani\",\"isPartOf\":{\"@id\":\"https:\/\/navveenbalani.dev\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#primaryimage\"},\"datePublished\":\"2010-05-28T17:29:18+00:00\",\"dateModified\":\"2017-03-24T12:35:45+00:00\",\"description\":\"Approach to handle pagination in dynamic pages -\",\"breadcrumb\":{\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/navveenbalani.dev\/\",\"url\":\"https:\/\/navveenbalani.dev\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/\",\"url\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/\",\"name\":\"Approach to handle pagination in dynamic pages\"}}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#webpage\"},\"author\":{\"@id\":\"https:\/\/navveenbalani.dev\/#\/schema\/person\/51f7ab14b20611d95e3c7fd4ea0950bf\"},\"headline\":\"Approach to handle pagination in dynamic pages\",\"datePublished\":\"2010-05-28T17:29:18+00:00\",\"dateModified\":\"2017-03-24T12:35:45+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#webpage\"},\"publisher\":{\"@id\":\"https:\/\/navveenbalani.dev\/#\/schema\/person\/51f7ab14b20611d95e3c7fd4ea0950bf\"},\"image\":{\"@id\":\"https:\/\/navveenbalani.dev\/index.php\/articles\/approach-to-handle-pagination-in-dynamic-pages\/#primaryimage\"},\"keywords\":\"Architecture,Pagination\",\"articleSection\":\"Architecture Patterns,Articles\",\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/navveenbalani.dev\/#\/schema\/person\/51f7ab14b20611d95e3c7fd4ea0950bf\",\"name\":\"Navveen\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/navveenbalani.dev\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/navveenbalani.dev\/wp-content\/uploads\/2019\/07\/navveen_balani.jpeg\",\"width\":200,\"height\":200,\"caption\":\"Navveen\"},\"logo\":{\"@id\":\"https:\/\/navveenbalani.dev\/#personlogo\"},\"sameAs\":[\"http:\/\/naveenbalani.com\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/posts\/277"}],"collection":[{"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/comments?post=277"}],"version-history":[{"count":10,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/posts\/277\/revisions"}],"predecessor-version":[{"id":2388,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/posts\/277\/revisions\/2388"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/media\/2128"}],"wp:attachment":[{"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/media?parent=277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/categories?post=277"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/navveenbalani.dev\/index.php\/wp-json\/wp\/v2\/tags?post=277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}