Search Requests > 500

This post will go over a new helper method for making search requests with a result greater than 500.

Overview of Issue

The max results the SharePoint REST Search query can have is 500. The PrimaryQueryResult.RelevantResults.TotalRows value will determine if there are more results available.

Overview of Solution

You need to compare the total rows returned with the number of rows in the table itself. If the total rows is greater than what was returned, then you need to make another request and set the StartRow property for the next set of results.

Code Samples

This code example will give an example of getting all of the site collections the user has access to.

Code Example (Helper Method)

This code example will use a new method for the Search module in the gd-sprest library. The helper method will default to the max results (500) and to use batch requests by default. These values can be customized through the properties.

import { Search, Types } from "gd-sprest";

// Site Information
interface ISiteInfo {
  Id?: string;
  Title?: string;
  Url?: string;
}

// Processes the results
function processResults(sites: Array<ISiteInfo>, results: Types.Microsoft.Office.Server.Search.REST.SearchResult) {
  // Parse the results
  for(let i=0; i<results.PrimaryQueryResult.RelevantResults.RowCount; i++) {
    let row = results.PrimaryQueryResult.RelevantResults.Table.Rows.results[i];
    let siteInfo:ISiteInfo = {};

    // Parse the cells
    for(let j=0; j<row.Cells.results.length; j++) {
      let cell = row.Cells.results[j];

      // Set the values
      switch(cell.Key) {
        case "SPSiteUrl":
          siteInfo.Url = cell.Value;
          break;
        case "Title":
          siteInfo.Title = cell.Value;
          break;
        case "WebId":
          siteInfo.Id = cell.Value;
          break;
      }
    }

    // Append the site
    sites.push(siteInfo);
  }
}

// Get all of the sites the user has access to
export function searchAllSites():PromiseLike<Array<ISiteInfo>> {
  // Return a promise
  return new Promise((resolve, reject) => {
    let sites:Array<ISiteInfo> = [];

    // Search for site collections
    Search.postQuery({
      // The search query (Row limit will be defaulted to 500)
      query: {
        Querytext: "contentclass=sts_site",
        TrimDuplicates: true,
        SelectProperties: {
          results: [
            "Title", "SPSiteUrl", "WebId"
          ]
        }
      },
      // We will process each request as they are completed
      onQueryCompleted: results => {
        // Process the results
        processResults(sites, results);
      }
    }).then(results => {
      // The results have been processed, so we can just resolve the request
      resolve(sites);
    });
  });
}

Code Example (Full Logic)

This will not use the helper method, but will explain what you would need to do in order to get all of the search results.

import { Search, Types } from "gd-sprest";

// Site Information
interface ISiteInfo {
  Id?: string;
  Title?: string;
  Url?: string;
}

// Processes the results
function processResults(sites: Array<ISiteInfo>, results: Types.Microsoft.Office.Server.Search.REST.SearchResult) {
  // Parse the results
  for(let i=0; i<results.PrimaryQueryResult.RelevantResults.RowCount; i++) {
    let row = results.PrimaryQueryResult.RelevantResults.Table.Rows.results[i];
    let siteInfo:ISiteInfo = {};

    // Parse the cells
    for(let j=0; j<row.Cells.results.length; j++) {
      let cell = row.Cells.results[j];

      // Set the values
      switch(cell.Key) {
        case "SPSiteUrl":
          siteInfo.Url = cell.Value;
          break;
        case "Title":
          siteInfo.Title = cell.Value;
          break;
        case "WebId":
          siteInfo.Id = cell.Value;
          break;
      }
    }

    // Append the site
    sites.push(siteInfo);
  }
}

// Get all of the sites the user has access to
export function searchAllSites():PromiseLike<Array<ISiteInfo>> {
  // Return a promise
  return new Promise((resolve, reject) => {
    // Search for site collections
    Search().postquery({
      Querytext: "contentclass=sts_site",
      RowLimit: 500,
      TrimDuplicates: true,
      SelectProperties: {
        results: [
          "Title", "SPSiteUrl", "WebId"
        ]
      }
    }).execute(results => {
      let sites:Array<ISiteInfo> = [];

      // Process the results
      processResults(sites, results.postquery);

      // See if more items exist
      if(results.postquery.PrimaryQueryResult.RelevantResults.TotalRows > sites.length) {
        let search = Search();
        let totalPages = Math.ceil(results.postquery.PrimaryQueryResult.RelevantResults.TotalRows / 500);

        // Parse the # of required requests
        for(let i=1; i<totalPages; i++) {
          // Create the batch request
          search.postquery({
            Querytext: "contentclass=sts_site",
            RowLimit: 500,
            StartRow: i*500,
            TrimDuplicates: true,
            SelectProperties: {
              results: [
                "Title", "SPSiteUrl", "WebId"
              ]
            }
          }).batch(results => {
            // Process the results
            processResults(sites, results.postquery);
          }, i%100); // Limit the # of requests to 100 per batch
        }

        // Execute the requests
        search.execute(() => {
          // Resolve the request
          resolve(sites);
        });
      } else {
        // Resolve the request
        resolve(sites);
      }
    });
  });
}

Summary

I highly recommend the search api. It’s very powerful and very useful. I hope this code example was helpful. Happy Coding!!!

Share: Twitter Facebook
Gunjan Datta's Picture

About Gunjan Datta

A SharePoint developer.

http://dattabase.com