{"id":1489,"date":"2015-07-22T09:49:41","date_gmt":"2015-07-22T04:19:41","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=1489"},"modified":"2022-06-24T15:02:50","modified_gmt":"2022-06-24T09:32:50","slug":"querying-more-than-5000-records-in-dynamics-crm","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2015\/07\/querying-more-than-5000-records-in-dynamics-crm\/","title":{"rendered":"Querying More than 5000 records in Dynamics CRM"},"content":{"rendered":"<h2>Introduction:<\/h2>\n<p>There are multiple ways provided in Dynamics CRM SDK to query and read data like<\/p>\n<ol>\n<li>Using ODATA<\/li>\n<li>Using FetchXML<\/li>\n<li>Using Query object<\/li>\n<\/ol>\n<p style=\"text-align: justify;\">ODATA has a limitation where it can return only 50 records at a time. You can ofcourse query more than that but it would be in batches of 50 records at a time.<\/p>\n<p style=\"text-align: justify;\">Fetch XML queries on the other hand will allow you to read upto 5000 records in one go with the ability to read the next 5000. Since requesting 5000 records at a time may not really be a good idea because of the network resources that would use and potentially slow down or even time out depending on the network speeds, it is always a good idea to read data in small manageable sets of records. Fetch queries when executed return paging cookies when you implement paging and this helps you to implement a system where you would like to read a fixed count of records and provide a next\/prev button to access additional records.<\/p>\n<h2>Query Records using Fetch<\/h2>\n<p>&lt;fetch mapping=&#8221;logical&#8221; output-format=&#8221;xml-platform&#8221; version=&#8221;1.0&#8243; page=&#8221;1&#8243; paging-cookie=&#8221;&#8221; &gt;<\/p>\n<p>&lt;entity name=&#8221;account&#8221; &gt;<\/p>\n<p>&lt;attribute name=&#8221;name&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;address1_city&#8221; \/&gt;<\/p>\n<p>&lt;order descending=&#8221;false&#8221; attribute=&#8221;name&#8221; \/&gt;<\/p>\n<p>&lt;filter type=&#8221;and&#8221; &gt;<\/p>\n<p>&lt;condition attribute=&#8221;ownerid&#8221; operator=&#8221;eq-userid&#8221; \/&gt;<\/p>\n<p>&lt;condition value=&#8221;0&#8243; attribute=&#8221;statecode&#8221; operator=&#8221;eq&#8221; \/&gt;<\/p>\n<p>&lt;\/filter&gt;<\/p>\n<p>&lt;attribute name=&#8221;primarycontactid&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;telephone1&#8243; \/&gt;<\/p>\n<p>&lt;link-entity visible=&#8221;false&#8221; name=&#8221;contact&#8221; link-type=&#8221;outer&#8221; to=&#8221;primarycontactid&#8221; from=&#8221;contactid&#8221; alias=&#8221;accountprimarycontactidcontactcontactid&#8221; &gt;<\/p>\n<p>&lt;attribute name=&#8221;emailaddress1&#8243; \/&gt;<\/p>\n<p>&lt;\/link-entity&gt;<\/p>\n<p>&lt;attribute name=&#8221;industrycode&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;donotbulkemail&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;creditonhold&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;accountid&#8221; \/&gt;<\/p>\n<p>&lt;\/entity&gt;<\/p>\n<p>&lt;\/fetch&gt;<\/p>\n<p style=\"text-align: justify;\">The above code works fine as long as there are less than 5000 records in the system. When the records fetched count went above 5000+ records we started getting following error:<\/p>\n<p><a href=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2015\/07\/report4.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1490\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2015\/07\/report4.png\" alt=\"report\" width=\"500\" height=\"190\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">So if you notice in our above fetch xml we are providing \u201cpaging-cookie\u201d as blank. So once the records retrieved count goes above 5000+ records we started getting the above shown error. For Fetch to bring records above 5000+ it requires paging-cookie to be set in the fetch tag<\/p>\n<h2>Setting the Paging Cookie<\/h2>\n<p style=\"text-align: justify;\">Where do we find the paging cookie?\u00a0 The answer is fetch response. Whenever we make a fetch request the response which we get back from fetch has paging-cookie in it. We need to extract that paging-cookie from response which we can send to our next page fetch request. In addition to paging-cookie we also get \u201cMoreRecords\u201d which is Boolean which tells us if there are any more records to fetch.<\/p>\n<p style=\"text-align: justify;\">When we are on first page we provide the paging-cookie as blank as the first page doesn\u2019t need a paging-cookie. When the fetch query is executed it brings the page-cookie with it in the resultant response which looks like this:<\/p>\n<p>&#8220;&lt;cookie page=\\&#8221;1\\&#8221;&gt;&lt;name lastnull=\\&#8221;1\\&#8221; firstnull=\\&#8221;1\\&#8221; \/&gt;&lt;accountid last=\\&#8221;{98B36F67-3A21-E511-80FC-C4346BAD2660}\\&#8221; first=\\&#8221;{A6B16F67-3A21-E511-80FC-C4346BAD2660}\\&#8221; \/&gt;&lt;\/cookie&gt;&#8221;<\/p>\n<p>To get this page-cookie from response we extract it from resultant fetch response as follows:<\/p>\n<p>Var pagecookie = $(resultXml).find(&#8220;a\\\\:PagingCookie&#8221;).eq(0)[0].text;<\/p>\n<p style=\"text-align: justify;\">You can find that since we are on first page it returns the page as \u201c1\u201d. Since the fetch is for \u201cAccount\u201d entity it returns the first accountid and last accountid for that page in page-cookie. When we request for the next page we provide this page-cookie from first page to the next page fetch query request.<\/p>\n<p>In the same way we can extract \u201cMoreRecords\u201d as follows:<\/p>\n<p>Var moreRecords = $(resultXml).find(&#8220;a\\\\:MoreRecords&#8221;).eq(0)[0].text<\/p>\n<p>This returns \u201ctrue\u201d or \u201cfalse\u201d which helps us to determine if we reached last page or still there are any records to fetch.<\/p>\n<h2>Updated Code<\/h2>\n<p>var xmlDocument = parser.parseFromString(fetchxml, &#8220;text\/xml&#8221;);<\/p>\n<p>var fetch = $(xmlDocument).find(&#8216;fetch&#8217;);<\/p>\n<p>fetch.attr(&#8216;page&#8217;, page);<\/p>\n<p>fetch.attr(&#8216;count&#8217;, pageCount);<\/p>\n<p>fetch.attr(&#8216;paging-cookie&#8217;, pagingCookie);<\/p>\n<p>In above code we are providing \u201cpagingCookie\u201d variable to which we set the page-cookie which we get from response in fetch attribute along with page and pagecount.<\/p>\n<p>So now when you checkout the fetch query it be as follows :<\/p>\n<p>&lt;fetch count=&#8221;250&#8243; mapping=&#8221;logical&#8221; output-format=&#8221;xml-platform&#8221; version=&#8221;1.0&#8243; page=&#8221;18&#8243; paging-cookie=&#8221;&amp;#60;cookie page&amp;#61;&amp;#34;1&amp;#34;&amp;#62;&amp;#60;name lastnull&amp;#61;&amp;#34;1&amp;#34; firstnull&amp;#61;&amp;#34;1&amp;#34; &amp;#47;&amp;#62;&amp;#60;accountid last&amp;#61;&amp;#34;&amp;#123;98B36F67-3A21-E511-80FC-C4346BAD2660&amp;#125;&amp;#34; first&amp;#61;&amp;#34;&amp;#123;A6B16F67-3A21-E511-80FC-C4346BAD2660&amp;#125;&amp;#34; &amp;#47;&amp;#62;&amp;#60;&amp;#47;cookie&amp;#62;&#8221; \/&gt;&lt;\/cookie&gt;&#8221;&gt;<\/p>\n<p>&lt;entity name=&#8221;account&#8221; &gt;<\/p>\n<p>&lt;attribute name=&#8221;name&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;address1_city&#8221; \/&gt;<\/p>\n<p>&lt;order descending=&#8221;false&#8221; attribute=&#8221;name&#8221; \/&gt;<\/p>\n<p>&lt;filter type=&#8221;and&#8221; &gt;<\/p>\n<p>&lt;condition attribute=&#8221;ownerid&#8221; operator=&#8221;eq-userid&#8221; \/&gt;<\/p>\n<p>&lt;condition value=&#8221;0&#8243; attribute=&#8221;statecode&#8221; operator=&#8221;eq&#8221; \/&gt;<\/p>\n<p>&lt;\/filter&gt;<\/p>\n<p>&lt;attribute name=&#8221;primarycontactid&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;telephone1&#8243; \/&gt;<\/p>\n<p>&lt;link-entity visible=&#8221;false&#8221; name=&#8221;contact&#8221; link-type=&#8221;outer&#8221; to=&#8221;primarycontactid&#8221; from=&#8221;contactid&#8221; alias=&#8221;accountprimarycontactidcontactcontactid&#8221; &gt;<\/p>\n<p>&lt;attribute name=&#8221;emailaddress1&#8243; \/&gt;<\/p>\n<p>&lt;\/link-entity&gt;<\/p>\n<p>&lt;attribute name=&#8221;industrycode&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;donotbulkemail&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;creditonhold&#8221; \/&gt;<\/p>\n<p>&lt;attribute name=&#8221;accountid&#8221; \/&gt;<\/p>\n<p>&lt;\/entity&gt;<\/p>\n<p>&lt;\/fetch&gt;<\/p>\n<p><strong>Note:<\/strong><\/p>\n<p style=\"text-align: justify;\">Make sure to encode the fetchxml request to cover for any special characters in the data. Let us explain with an example, for one of the result sets of the above fetch we found the paging-cookie received a special character \u2013 single quote (\u2018) in one of the records name field. This field was referenced in the paging-cookie.<\/p>\n<p>Example:<\/p>\n<p>&#8220;&lt;cookie page=\\&#8221;2\\&#8221;&gt;&lt;fullname last=\\&#8221;Susan\u2019s Burk (sample)\\&#8221; first=\\&#8221;Rene Valdes (sample)\\&#8221; \/&gt;&lt;contactid last=\\&#8221;{349DB5FF-DA1B-E511-80F1-C4346BACD1A8}\\&#8221; first=\\&#8221;{2E9DB5FF-DA1B-E511-80F1-C4346BACD1A8}\\&#8221; \/&gt;&lt;\/cookie&gt;&#8221;<\/p>\n<p style=\"text-align: justify;\">In above example you can see that the fullname last=\\&#8221;Susan\u2019s Burk (sample)\\&#8221; has (\u2018s). This (\u2018) used to break the fetchxml and hence started throwing \u201c<strong>Page Cookie Malformed<\/strong>\u201d exception when trying to execute fetchxml request.<\/p>\n<p style=\"text-align: justify;\">To resolve this you need to encode the paging-cookie before it is insert in the fetch xml.<\/p>\n<h2>Traversing backwards<\/h2>\n<p style=\"text-align: justify;\">Using the paging-cookie you can traverse forward to the next set of results. But if you want to implement the previous button or you want to allow navigation to a specific page, you need to make sure you store the paging-cookie received for each of the pages.<\/p>\n<p style=\"text-align: justify;\">To deal with this you can save the page-cookie for example in the array for the pages which you move forward and use this later to get the page-cookie for that particular page when moving backward in paging.<\/p>\n<h2>Conclusion<\/h2>\n<p style=\"text-align: justify;\">Using Paging-cookies effectively, you can implement paging without actually retrieving all the records at one-go. Query records only when requested and display for better performance results.<\/p>\n<h2 style=\"text-align: left;\"><div class=\"su-heading su-heading-style-default su-heading-align-center\" id=\"\" style=\"font-size:15px;margin-bottom:5px\"><div class=\"su-heading-inner\">One Pic = 1000 words! Analyze data 90% faster with visualization apps!<\/div><\/div><\/h2>\n<p style=\"text-align: left;\"><em>Get optimum visualization of Dynamics 365 CRM data with &#8211;<\/em><br \/>\n<em><strong><a href=\"https:\/\/bit.ly\/3lYvozZ\" target=\"_blank\" rel=\"noopener noreferrer\">Kanban Board<\/a> <\/strong>\u2013 Visualize Dynamics 365 CRM data in Kanban view by categorizing entity records in lanes and rows as per their status, priority, etc.<\/em><br \/>\n<em><strong><a href=\"https:\/\/bit.ly\/3lCSBaA\" target=\"_blank\" rel=\"noopener noreferrer\">Map My Relationships<\/a><\/strong> \u2013 Map My Relationships \u2013 Visualize connections and relationships between Dynamics 365 CRM entities or related records in a Mind Map view.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction: There are multiple ways provided in Dynamics CRM SDK to query and read data like Using ODATA Using FetchXML Using Query object ODATA has a limitation where it can return only 50 records at a time. You can ofcourse query more than that but it would be in batches of 50 records at a\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2015\/07\/querying-more-than-5000-records-in-dynamics-crm\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":13,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[19,21,22,24,33,39,42],"tags":[395,592,597],"class_list":["post-1489","post","type-post","status-publish","format-standard","hentry","category-dynamics-crm","category-dynamics-crm-2013","category-dynamics-crm-2015","category-dynamics-crm-2016","category-javascript","category-miscellaneous","category-plugin","tag-crm-2013-dynamics-crm-2013","tag-dynamics-crm","tag-dynamics-crm-2015"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/1489","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=1489"}],"version-history":[{"count":0,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/1489\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=1489"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=1489"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=1489"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}