allBlogsList

Add Sorting to the GraphQL Search Query

If you have started using JSS, then you are likely familiar with (or becoming familiar with) leveraging GraphQL to retrieve data for your site and components. Sitecore delivers two queries OOTB with the JSS package for GraphQL:

  • Item Query - get items and data directly from Sitecore
  • Search Query - get item data from Solr

The process for building a search query is pretty simple, and includes a few parameters you can use to retrieve your data:

  • rootItem - the root item for your search, as a path or ID
  • keyword - a string that searches the `Content` field of a Solr result
  • language - language version to pull back
  • latestVersion - version to retrieve; otherwise will return latest version
  • index - the index to search
  • fieldEquals - an array of {name: "...", value: "..."} objects to use for equality checks of data retrieval.
  • facetOn - an array of field names to return facet data on the search results
  • after - integer value to use for paging your data.

The parameters that are passed in are used to build a predicate and fired off for search results from the Search API. The OOTB parameters allow for very powerful and fast queries for data but are limiting by a key factor. It does not support sorting, so you cannot control the order in which your results are returned. In a recent implementation, we had to add sorting to allow us to retrieve data sorted by date. Lucky for us, this was already done by a colleague (Uy Tran). He was nice enough to share his implementation with us, and I am sharing it with anyone else who might need it.

Support for sorting requires two things:

  1. Modifying the constructor to take additional parameters
  2. Modifying the ResolveContents method to process the new parameter

First things first, create a new class that extends the existing SearchQuery implementation. In the constructor for this new class, add two new parameters to the list of QueryArguments.

public class ExtendedSearchQuery : Sitecore.Services.GraphQL.Content.Queries.SearchQuery
{
    public ExtendedSearchQuery()
    {
        this.Arguments.Add(new QueryArgument<StringGraphType>()
        {
            Name = "sortBy",
            Description = "Sort by a field"
        });

        this.Arguments.Add(new QueryArgument<BooleanGraphType>()
        {
            Name = "sortDesc",
            Description = "Specify Desc vs ascending",
            DefaultValue = false
        });
    }
}

sortBy will be used to define what field we want to ... sort by. And sortDesc is a parameter to define the sort order.

The arguments are accepted by GraphQL, so now we have to inform the system on how to translate them. To do this, we override the ResolveContents method. In the interest of brevity, I am only going to include the changes that were made to the method:

protected override ContentSearchResults Resolve(ResolveFieldContext context)
{
	// original Sitecore code here

	using (var searchContext = index.CreateSearchContext())
	{
		// original Sitecore code here
		
		// add sorting support
		if (!string.IsNullOrEmpty(sortBy))
		{
			if (sortDesc.HasValue && sortDesc == true)
			{
				queryable = queryable.OrderByDescending(result => result[sortBy]);
			}
			else
			{
				queryable = queryable.OrderBy(result => result[sortBy]);
			}
		}

		var results = new ContentSearchResults(
			queryable.ApplyEnumerableConnectionArguments<ContentSearchResult, object>(context).GetResults(),
			nullable2 ?? 0);

		return results;
	}
}

The above code takes the predicate that we build and applies our passed in sorting parameter and ascending/descending options. One thing to note: when accessing the fields on your result object, they are all referenced as a string. Most standard sorting will work, but it likely won't give you the desired result if you're trying to sort something like a date. To do this, you will need to convert your date field to a string-sortable friendly value. My recommendation is to create a computed index for your date fields to store the value in ticks.

You can find the full implementation for the ExtendedSearchQuery in a gist here: ExtendedSitecoreQuery.

Hopefully, this helps with a future implementation for your site. Happy Sitecore'ing!!!