{"id":4624,"date":"2020-05-19T07:55:46","date_gmt":"2020-05-19T14:55:46","guid":{"rendered":"https:\/\/officedevblogs.wpengine.com\/?p=4624"},"modified":"2020-05-19T07:55:46","modified_gmt":"2020-05-19T14:55:46","slug":"build-advanced-queries-with-count-filter-search-and-orderby","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/build-advanced-queries-with-count-filter-search-and-orderby\/","title":{"rendered":"Build advanced queries in Microsoft Graph with $count, $filter, $search, and $orderby"},"content":{"rendered":"<p><strong>UPDATE 9\/22: read the <a href=\"https:\/\/aka.ms\/BlogPostMezzoGA\">General Availability announcement<\/a>.<\/strong><\/p>\n<p>Some of the top asks we have received on Azure Active Directory were for better sorting, counting, and filtering capabilities. We are excited to announce that we are now providing these capabilities on Azure Active Directory objects to developers through Microsoft Graph! In addition to addressing these important requests, we\u2019ve added the ability to provide keyword-based searches.<\/p>\n<p>In the past, if you\u2019ve tried to filter and sort users in the same request, using a query like this:<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\" class=\"\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=users?$filter=startswith(displayName,%20%27al%27)%26$orderby=displayName%26$select=id,displayName&amp;method=GET&amp;version=v1.0&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/v1.0\/users?$filter=startswith(displayName, 'al')&amp;$orderby=displayName&amp;$select=id,displayName<\/pre>\n<p>You might have seen the following response:<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\" class=\"\"><span style=\"color: #a31515\">\"error\"<\/span>: {\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #a31515\">\"code\"<\/span>: <span style=\"color: #0451a5\">\"Request_UnsupportedQuery\"<\/span>,\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #a31515\">\"message\"<\/span>: <span style=\"color: #0451a5\">\"Sorting not supported for current query.\"<\/span>\n}<\/pre>\n<p>Now, this will result in a sorted list of users, with a new <code class=\"language-plaintext\">@odata.count<\/code> property:<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\" class=\"\"><span style=\"color: #a31515\">\"@odata.context\"<\/span>: <span style=\"color: #0451a5\">\"https:\/\/graph.microsoft.com\/beta\/$metadata#users(id,displayName)\"<\/span>,\n<span style=\"color: #a31515\">\"@odata.count\"<\/span>: <span style=\"color: #09885a\">2<\/span>,\n<span style=\"color: #a31515\">\"value\"<\/span>: [\n   {\n      <span style=\"color: #a31515\">\"id\"<\/span>: <span style=\"color: #0451a5\">\"4782e723-f4f4-4af3-a76e-25e3bab0d896\"<\/span>,\n      <span style=\"color: #a31515\">\"displayName\"<\/span>: <span style=\"color: #0451a5\">\"Alex Wilber\"<\/span>\n   },\n   {\n      <span style=\"color: #a31515\">\"id\"<\/span>: <span style=\"color: #0451a5\">\"c03e6eaa-b6ab-46d7-905b-73ec7ea1f755\"<\/span>,\n      <span style=\"color: #a31515\">\"displayName\"<\/span>: <span style=\"color: #0451a5\">\"Allan Deyoung\"<\/span>\n   }\n]<\/pre>\n<p style=\"padding-top: 0.5rem\"><strong>To achieve this, you need to:<\/strong><\/p>\n<ol>\n<li>Select the beta endpoint<\/li>\n<li>Add <code class=\"language-plaintext\">$count=true<\/code> in the QueryString<\/li>\n<li>Add <code class=\"language-plaintext\">ConsistencyLevel = eventual<\/code> to the Request headers<\/li>\n<\/ol>\n<p style=\"padding: 0px\"><img decoding=\"async\" class=\"alignnone size-large wp-image-4625\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/05\/Mezzos-1024x373.png\" alt=\"graph explorer query\" width=\"1024\" height=\"373\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/05\/Mezzos-1024x373.png 1024w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/05\/Mezzos-300x109.png 300w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/05\/Mezzos-768x280.png 768w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2020\/05\/Mezzos.png 1345w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h3 style=\"padding-top: 18px\">Supported Objects<\/h3>\n<p style=\"padding: 0\">In the table below there are all the objects and related links that currently have the new advanced querying capabilities.<\/p>\n<table>\n<tbody style=\"vertical-align: top\">\n<tr style=\"border-bottom: 1px solid #ddd\">\n<td><b>Object<\/b><\/td>\n<td><b>Links<\/b><\/td>\n<\/tr>\n<tr>\n<td>Users<\/td>\n<td>Member Of, Transitive Member Of, Owned Objects, Registered Devices,\nOwned Devices, Direct Reports<\/td>\n<\/tr>\n<tr>\n<td>Groups<\/td>\n<td>Members, Transitive Members, Owners<\/td>\n<\/tr>\n<tr>\n<td>Applications<\/td>\n<td>Member Of, Transitive Member Of<\/td>\n<\/tr>\n<tr>\n<td>Service Principals<\/td>\n<td>Member Of, Transitive Member Of<\/td>\n<\/tr>\n<tr>\n<td>Devices<\/td>\n<td>Member Of, Transitive Member Of, Registered Users, Registered Owners<\/td>\n<\/tr>\n<tr>\n<td>Org Contacts<\/td>\n<td>Member Of, Transitive Member Of, Registered Users, Registered Owners<\/td>\n<\/tr>\n<tr>\n<td>Administrative Units<\/td>\n<td>Members<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 style=\"padding-top: 18px\">What is eventual consistency?<\/h3>\n<p style=\"padding: 0px\">Azure Active Directory stores multiple copies of data to handle large read volume and provide high availability. When data is updated, the change will eventually be applied to all the copies.\n<code class=\"language-plaintext\">$search<\/code> and <code class=\"language-plaintext\">$count<\/code> queries require the client to opt-in for eventual consistency by setting the header <code class=\"language-plaintext\">ConsistencyLevel = eventual<\/code>.\nFor example, this means that when you add a user, you need to wait for all the copies to be updated to search or count them.<\/p>\n<h3 style=\"padding-top: 18px\">Sample Queries<\/h3>\n<p style=\"padding: 0px\"><a href=\"https:\/\/docs.microsoft.com\/en-us\/graph\/query-parameters?#count-parameter\" target=\"_blank\" rel=\"noopener noreferrer\">Count the number<\/a> of users, groups, applications, contacts, devices, service principals in a tenant, answering questions like:<\/p>\n<p>\u25fe How many users are in the tenant?<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\" class=\"\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=users\/$count&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/users\/$count<\/pre>\n<p style=\"padding: 0px\">\u25fe How many guest users are in the tenant, and who are they? <em><strong>Note<\/strong>: <code class=\"language-plaintext\">$count<\/code> can also be a QueryString parameter.<\/em><\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=users?$count=true%26$filter=userType%20eq%20%27Guest%27&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/users\/?$count=true&amp;$filter=userType eq \u2018Guest\u2019<\/pre>\n<p style=\"padding: 0px\">\u25fe How many members are in the engineering group (including transitive and direct members of a group)?<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=groups\/9a6a616e-5637-4306-b1fe-bceeaa750873\/transitiveMembers\/$count&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/groups\/{group-id}\/transitiveMembers\/$count<\/pre>\n<p style=\"padding: 0px\"><em><strong>Note<\/strong>: A group can contain nested groups, so we are using the\u00a0transitiveMembers\u00a0linked property to include all the nested groups\u2019 members.<\/em><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/graph\/query-parameters?#using-search-on-directory-object-collections\" target=\"_blank\" rel=\"noopener noreferrer\">Search terms using tokenization<\/a>. We are using a tokenization approach for our searches, detailed as follows:<\/p>\n<ul>\n<li>Spaces: <code style=\"background-color: #f2f4f5\">hello world<\/code> will be tokenized in <code style=\"background-color: #f2f4f5\">hello<\/code> and <code style=\"background-color: #f2f4f5\">world<\/code><\/li>\n<li>Different casing: <code style=\"background-color: #f2f4f5\">HelloWorld<\/code> and <code style=\"background-color: #f2f4f5\">helloWORLD<\/code> will be tokenized in <code style=\"background-color: #f2f4f5\">hello<\/code> and <code style=\"background-color: #f2f4f5\">world<\/code><\/li>\n<li>Special characters: <code style=\"background-color: #f2f4f5\">hello.world<\/code> will be tokenized in <code style=\"background-color: #f2f4f5\">hello<\/code>, <code style=\"background-color: #f2f4f5\">.<\/code> and <code style=\"background-color: #f2f4f5\">world<\/code><\/li>\n<li>Characters and Numbers: <code style=\"background-color: #f2f4f5\">hello123<\/code> will be tokenized in <code style=\"background-color: #f2f4f5\">hello<\/code> and <code style=\"background-color: #f2f4f5\">123<\/code><\/li>\n<\/ul>\n<p style=\"padding: 0px\"><em><strong>Note<\/strong>: tokenized search is currently limited to <code>displayName<\/code> and <code>description<\/code> properties for now. All the other properties default to the <code class=\"language-plaintext\">startsWith<\/code> behavior.\nWe currently don&#8217;t offer true substring searches because it will affect the overall search performance. Searching for <code style=\"background-color: #f2f4f5\">world<\/code> will <strong>not<\/strong> find <code style=\"background-color: #f2f4f5\">helloworld<\/code>.<\/em><\/p>\n<p>\u25fe Search for users with \u201cde\u201d in the displayName<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=users?$count=true%26$search=%22displayName:de%22%26$select=id,displayName&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/users?$count=true&amp;$search=\"displayName:de\"<\/pre>\n<p style=\"padding: 0px\">\u25fe Search for all users in a with &#8220;al&#8221; in the displayName or with mail <em>starting with<\/em> \u2018admin\u2019, sorted by displayName<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=users?$count=true%26$search=%22displayName:al%22%20OR%20%22mail:admin%22%26select=id,displayName,mail&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/users?$count=true&amp;$search=\"displayName:al\" OR \"mail:admin\"&amp;$orderBy=displayName<\/pre>\n<p style=\"padding: 0px\">\u25fe Search for service principals with \u201cteam\u201d in the displayName<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=servicePrincipals?$count=true%26$search=%22displayName:team%22%26$select=id,displayName&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/servicePrincipals?$count=true&amp;$search=\"displayName:team\"<\/pre>\n<p style=\"padding: 0px\">\u25fe Search in a group transitively for all members with \u201cbr\u201d in the displayName<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=groups\/9a6a616e-5637-4306-b1fe-bceeaa750873\/transitiveMembers\/microsoft.graph.user\/?$count=true%26$search=%22displayName:br%22%26$select=id,displayName&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\" target=\"_blank\" rel=\"noopener noreferrer\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/groups\/{group-id}\/transitiveMembers\/microsoft.graph.user\/?$count=true&amp;$search=\"displayName:br\"<\/pre>\n<p style=\"padding: 0px\"><em><strong>Note<\/strong>: OData Cast provides a way to trim the results to a specific object type. Group members can be of the following types: users, applications, service principals, devices. In the previous example, specifying <code class=\"language-plaintext\">\/microsoft.graph.user<\/code> in the URL will return only the users in the group.<\/em><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/graph\/query-parameters#orderby-parameter\" target=\"_blank\" rel=\"noopener noreferrer\">Sorting<\/a> can be combined with filter or search, but is limited to <strong>displayName<\/strong> and <strong>userPrincipalName<\/strong> properties for now.<\/p>\n<p style=\"padding-top: 1rem\">\u25fe Sort users in building 18 by displayName:<\/p>\n<pre style=\"padding: 0.5rem;margin: 0px\"><a href=\"https:\/\/developer.microsoft.com\/en-US\/graph\/graph-explorer\/preview?request=users?$count=true%26$orderby=displayName%26$filter=startswith(officeLocation,%20%2718%27)%26select=id,displayName,officeLocation&amp;method=GET&amp;version=beta&amp;GraphUrl=https:\/\/graph.microsoft.com&amp;requestBody=&amp;headers=W3sibmFtZSI6IkNvbnNpc3RlbmN5TGV2ZWwiLCJ2YWx1ZSI6ImV2ZW50dWFsIn1d\">GET<\/a> https:\/\/graph.microsoft.com\/beta\/users?$count=true&amp;$orderby=displayName&amp;$filter=startswith(officeLocation, '18')<\/pre>\n<p style=\"padding-top: 6px\">As always, you can send multiple requests at the same time <a href=\"https:\/\/docs.microsoft.com\/en-us\/graph\/json-batching\" target=\"_blank\" rel=\"noopener noreferrer\">using JSON batching<\/a>.<\/p>\n<h3 style=\"padding-top: 18px\">Try it now!<\/h3>\n<p style=\"padding: 0px\">We&#8217;ve heard your feedback and have addressed some of the top requests on UserVoice such as:<\/p>\n<ul>\n<li><a href=\"https:\/\/microsoftgraph.uservoice.com\/forums\/920506-microsoft-graph-feature-requests\/suggestions\/37961185-support-the-count-operator-for-user-and-group-obj\" target=\"_blank\" rel=\"noopener noreferrer\">Support the $count operator for user and group objects<\/a><\/li>\n<li><a href=\"https:\/\/microsoftgraph.uservoice.com\/forums\/920506-microsoft-graph-feature-requests\/suggestions\/35630488-enable-filter-on-group-members\" target=\"_blank\" rel=\"noopener noreferrer\">Enable $filter on group members<\/a><\/li>\n<li><a href=\"https:\/\/microsoftgraph.uservoice.com\/forums\/920506-microsoft-graph-feature-requests\/suggestions\/35467792-enable-combining-filter-and-orderby-on-users-endpo\" target=\"_blank\" rel=\"noopener noreferrer\">Enable combining filter and orderBy on users endpoint<\/a><\/li>\n<li><a href=\"https:\/\/microsoftgraph.uservoice.com\/forums\/920506-microsoft-graph-feature-requests\/suggestions\/32706631-support-count-for-group-members-and-owners\" target=\"_blank\" rel=\"noopener noreferrer\">Support $count for group members and owners<\/a><\/li>\n<\/ul>\n<p>We cannot wait to see what you can create with these new features. To try our queries, just click the \u201cGET\u201d link in the examples above.<\/p>\n<p>As you use our APIs, please let us know what other objects, properties and fields you need to query to enable your scenarios in <a href=\"https:\/\/aka.ms\/MSGraphAADSurvey\" target=\"_blank\" rel=\"noopener noreferrer\">this brief survey<\/a> and <a href=\"https:\/\/microsoftgraph.uservoice.com\/forums\/920506-microsoft-graph-feature-requests\" target=\"_blank\" rel=\"noopener noreferrer\">UserVoice<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>UPDATE 9\/22: read the General Availability announcement. Some of the top asks we have received on Azure Active Directory were for better sorting, counting, and filtering capabilities. We are excited to announce that we are now providing these capabilities on Azure Active Directory objects to developers through Microsoft Graph! In addition to addressing these important [&hellip;]<\/p>\n","protected":false},"author":69081,"featured_media":25159,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3,5],"tags":[22],"class_list":["post-4624","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-graph","category-microsoft-identity-platform","tag-azure-ad"],"acf":[],"blog_post_summary":"<p>UPDATE 9\/22: read the General Availability announcement. Some of the top asks we have received on Azure Active Directory were for better sorting, counting, and filtering capabilities. We are excited to announce that we are now providing these capabilities on Azure Active Directory objects to developers through Microsoft Graph! In addition to addressing these important [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/4624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/69081"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=4624"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/4624\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/25159"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=4624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=4624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=4624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}