Support Relative Fast Queries for Lookup Fields in the Sitecore ASP.NET CMS

This blog post explains how you can add support for relative fast queries when looking up items to populate selection fields for data templates in the Sitecore ASP.NET CMS.

You can run Sitecore queries relative to items, but you can only run fast queries against an entire database. For example, if the Source property of a Multilist field in the /sitecore/content/Home item contains a value such as the following:

query:fast:.//*[@@templatekey='sample item']

You will experience an exception such as the following when you navigate to the /sitecore/content/Home item in the Content Editor:

Exception: Sitecore.Exceptions.LookupSourceException
Invalid lookup source "query:fast:.//*[@@templatekey='sample item']": End of string expected at position 4

To enable support for some types of relative fast queries, you can convert tokens that indicate relative paths to full paths before processing fast queries. To enable support for relative fast queries, you can add a processor such as the following to the getLookupSourceItems pipeline:

namespace Sitecore.Sharedsource.Pipelines.GetLookupSourceItems
  using System;
  using SC = Sitecore;
  public class HandleRelativeFastQuery
    public void Process(
      Sitecore.Pipelines.GetLookupSourceItems.GetLookupSourceItemsArgs args)
      SC.Diagnostics.Assert.ArgumentNotNull(args, "args");
      if (String.IsNullOrEmpty(args.Source)
        || !args.Source.StartsWith("query:fast:."))
      SC.Diagnostics.Assert.ArgumentNotNull(args.Item, "args.Item");
      SC.Data.Items.Item item = args.Item;
      string path = args.Source.Substring("query:fast:".Length);
      while (path.StartsWith("../"))
        item = item.Parent;
        path = path.Substring("../".Length);
      if (path.StartsWith("./"))
        path = path.Substring("./".Length);
      args.Source = "query:fast:" + item.Paths.FullPath + '/' + path;

Now when you access the /sitecore/content/Home item, the processor expands the query to the following before a the default ProcessQuerySource processor processes that query:

/sitecore/content/Home//*[@@templatekey='sample item']

You can use similar logic wherever you need to invoke a relative fast query. Remember to consider the limitations of fast query and always test whether fast query outperforms Sitecore query (before evaluating performance, run the query to ensure Sitecore has cached the items).

To enable this processor, you can use a Web.config include file such as the following (Sitecore.Sharedsource.HandleRelativeFastQuery.config in my case), which must appear before the default ProcessQuerySource processor in that pipeline:

<configuration xmlns:patch="">
        <processor type="Sitecore.Sharedsource.Pipelines.GetLookupSourceItems.HandleRelativeFastQuery, Sitecore.Sharedsource" 
          patch:before="processor[1]" />

Note that there may be types of relative queries that this does not support, such as queries that start with an XPath axis such as self, parent, or ancestor-or-self.