Generic Multilist Computed Field in Coveo for Sitecore

Posted 08/10/2014 by Akshay Sura

Computed fields are very useful, especially if you are implementing a multi-site / multi-lingual Sitecore solution. In some of the previous blog posts, we have covered foreign keys, auto suggestions and other important topics related to Coveo JS Framework.

In this post we will concentrate on multilist fields and how to create ONE generic unit of code that can handle either text or guids in the computed fields. Generally if you were to add a computed field, you need a piece of configuration as shown below and a class to perform the work needed to generate the output for the computed field. 

YOURNAMESPACE.Business.Search.ComputedFields.CUSTOMFIELDComputedField,YOURNAMESPACE.Business

This gets very tedious as you are creating multiple fields that store a delimited list of text or guids in the raw. Here is a great solution to cut down on code but achieve the same functionality. First we need configuration where we can call the same class but pass in the values. Here is a sample piece of config:

YOURNAMESPACE.Business.Search.ComputedFields.MultilistComputedField, YOURNAMESPACE.Business

YOURNAMESPACE.Business.Search.ComputedFields.MultilistComputedField, YOURNAMESPACE.Business YOURNAMESPACES.Business.Search.ComputedFields.MultilistComputedField, YOURNAMESPACE.Business

As you can see, we are calling the same code to generate the computed field value but we are passing in additional parameters via the config to specify which fields we want processed. Now for some code! As with any other computed field, we need to create a class which inherits IComputedField. The difference is that we need to pull in the additional configuration. Checkout the code below:

namespace YOURNAMESPACE.Business.Search.ComputedFields
{
    public class MultilistComputedField : IComputedIndexField
    {
        #region PrivateProtected
        //store xml configuration
        private readonly XmlNode m_Configuration;

        protected string GetConfigurationValue(string p_ConfigurationKey)
        {
            string configurationValue = null;
            if (m_Configuration != null && m_Configuration.Attributes != null)
            {
                XmlAttribute configurationAttribute = m_Configuration.Attributes[p_ConfigurationKey];
                if (configurationAttribute != null)
                {
                    configurationValue = configurationAttribute.Value;
                }
            }
            return configurationValue;
        }

        protected string PrimaryField
        {
            get
            {
                return GetConfigurationValue(Constants.Global.IndexFields.ComputedFieldPrimary);
            }
        }

        protected string LookupField
        {
            get
            {
                return GetConfigurationValue(Constants.Global.IndexFields.ComputedFieldLookup);
            }
        }
        #endregion

        #region Properties
        /// 
        public string FieldName
        {
            get;
            set;
        }
        /// 
        public string ReturnType
        {
            get;
            set;
        }
        #endregion


        #region Public Methods

        public MultilistComputedField(XmlNode p_Configuration)
        {
            m_Configuration = p_Configuration;
        }

        /// 
        public object ComputeFieldValue(IIndexable p_Indexable)
        {
            //get the primary field 
            IIndexableDataField multivalueField = p_Indexable.GetFieldByName(PrimaryField);
            Item currentItem = (Item)(p_Indexable as SitecoreIndexableItem);
            //check for null
            if (multivalueField != null && currentItem != null)
            {
                string fieldValue = multivalueField.Value.ToString();
                //if the field has values
                if (!string.IsNullOrEmpty(fieldValue))
                {
                    List guids = fieldValue.Split('|').ToList(); //split the fields using a pipe delimiter
                    List returnVals = new List();

                    //get the master database
                    Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
                    foreach (string guid in guids)
                    {
                        //if we have a valid id, get the item
                        ID refID;
                        if (ID.TryParse(guid, out refID))
                        {
                            Item tempItem = master.GetItem(refID, currentItem.Language);
                            if (tempItem != null)
                            {
                                //if value is returned add it to the collection
                                returnVals.Add(tempItem.Fields[LookupField].ToString());
                            }
                        }
                        else //process it as text
                        {
                            Log.Warn(string.Format("Textbased Multivalue: Parent ID:{0} GUID:{1} Primary Field:{2} Lookup Field:{3}", p_Indexable.Id.ToString(), guid, PrimaryField, LookupField), this);
                            returnVals.Add(guid);
                        }
                    }
                    //return values with semi-colon delimited
                    return string.Join(";", returnVals);
                }
            }
            return null;
        }

        #endregion

    }
}

The ComputedFieldValue method exists as in any other computed field implementation, the difference is the constructor that takes in the XmlNode and when the properties are called we extract the attributes. I hope this helps you with your computed fields, let me know if you have any questions or need additional information.