Sitecore query items returning out of order

Posted by & filed under , .

I’ve received questions about this a few times, so I decided to write a post on the issue. The problem people complain about is that they aren’t getting back Sitecore items in the same order they appear in the content tree. Sometimes they were previously getting them back in the right order, but now they’re “suddenly” coming back in a seemingly random order.

The culprit here is Sitecore Fast Query. Sitecore has the ability to speed up the query results by simply (believe it or not) adding the text “fast:” in front of the query. (Fast Queries can do more than simply speed up a normal query, for more information I suggest checking out briancaos’s blog post on the subject).

Example:
MySitecore.SelectItems(“/sitecore/content//*[@@templatekey= ‘my activity’]

becomes:
MySitecore.SelectItems(“fast:/sitecore/content//*[@@templatekey= ‘my activity’]

Part of the “fast” in Fast Query comes from tossing out some extras, including sorting the results before passing them back. If your results were previously coming back in an order that matched the Content Tree, but now are coming back in a seemingly random order, it’s likely that someone modified the query to be a Fast Query.

The solution is either to revert to a standard query (just remove the “fast:” from the front of the string) or to sort the results after getting them. Depending on the number of results, and where these results are located (basically how complicated it will be to sort them) it can be much faster to sort them after making the query.

We can use the Developer Center XPath Builder to measure the speed difference. In one example, we had 10 results coming back. It took 365ms for the standard query, but only 65ms for the Fast Query. In this case, it’s easy to sort the 10 items in our code and it will definitely take less than 300ms to run this code for 10 items, so we opted to use the Fast Query.

However, if we’re really going to mirror the content tree order, we need to understand how Sitecore actually sorts these items. Here are the basic rules it follows:

Note: All Items have a __sortorder field, this field is used to determine the ordering between sibling items (that is, there is no “master” number that determines the place in the tree, its simply sorting a node relative to its siblings, and then sorting its children’s nodes relative to *their* siblings that builds the order in the tree), therefore this set of rules only applies to sibling items.

  1. Sort by __sortorder field, if the value is empty, assume 100
  2. Items with the same __sortorder value are sorted by name
__sortorder only has a value “if it needs it” meaning that if your items are all in alphabetical order, they probably won’t have __sortorder values, since the assumed value of 100 will allow them to compare to one another with just the alphabetical sorting.

This means, as long as we know the items we’re getting are all siblings, we can use the following code to sort them with the same logic the Content Tree does:

        /// <summary>
        /// Sort a list of Items the same way that Sitecore does when it displays them in the tree
        /// </summary>
        /// <param name="itemList">List to be sorted</param>
        /// <returns>Sorted list</returns>
        public static List<Item> SitecoreSort(List<Item> itemList)
        {
            // Sort by sortvalue, if value is empty, assume 100. 
            // Sort items with the same sort value by Name. 
            // This is the way Sitecore does it, so we do the same.
            itemList.Sort((a, b) => (a.Fields["__sortorder"].Value == "" ? "100" : a.Fields["__sortorder"].Value) == (b.Fields["__sortorder"].Value == "" ? "100" : b.Fields["__sortorder"].Value) ?
                string.Compare(a.Name, b.Name) : int.Parse(a.Fields["__sortorder"].Value == "" ? "100" :
                a.Fields["__sortorder"].Value).CompareTo(int.Parse(b.Fields["__sortorder"].Value == "" ? "100" : b.Fields["__sortorder"].Value)));
            return itemList;
        }

If you fed a list of non-siblings in here, it’s not likely to work well, since all the siblings are sorted relative to one another, the __sortorder becomes meaningless when spread across different parent nodes.

If we wanted to support sorting non-sibling items, the logic become a bit more complex, since you have to start figuring out where items are relative to one another in the tree, and then comparing where their parent items are relative to each other, and at what depth, etc. At that point it starts becoming less and less worth it to use the Fast Query, and much more appealing to let Sitecore sort it for us.