Query Solr Documents from Pipeline Block in Sitecore Commerce

Sitecore commerce has its own set of indexes called the CatalogScope, OrderScope and CustomerScope. If we want to perform a search on these index, we can use some of the ootb commands. For example, if there is a need to lookup a sellable item entity id by display name, we can query the Solr documents in the CatalogScope index. This blog explains how to make calls to solr from a Sitecore Commerce pipeline block

Let's say for example, you are exposing an API in the commerce for another system (System XYZ) to consume. System XYZ does not have the sellable item entity id in its system, but has the product display name. So, the system XYZ will request sellable item details via a display name and expects in return a custom object that tells the current promotions active on the sellable item.

How do we find the entity id of the product from the display name? Simple, query the index CatalogScope

Sample catalog scope document

{ "sitecoreid":"ef5789c7-3680-12f3-cc95-c143f119b80f", "entityid":"Entity-SellableItem-6001009", "entityversion":1, "productid":"6001009", "displayname":"Warranty Bundle", "name":"WarrantyBundle", "datecreated":"2019-04-18T02:43:50.261Z", "dateupdated":"2019-04-18T02:43:50.397Z", "artifactstoreid":"78a1ea61-1f37-42a7-ac89-9a3f46d60ca5", "_version_":1631174810817003520},

We can see that there is a display name in the document, so we can perform a search by display name.

Now how to actually perform the search in the commerce block?

Use SolrContextCommand

Add the following using statements

using Sitecore.Commerce.Plugin.Search;
using Sitecore.Commerce.Plugin.Search.Solr;

Add the property and initialize it using DI in the constructor of the block

 private readonly SolrContextCommand _searchCommand;

In the block Run method:

	  var queryOptions = new QueryOptions()
                    Stats = new StatsParameters()
 var policy = context.GetPolicy<SearchScopePolicy>(); //SearchScopePolicy has the index details

                var filter = $"displayName=\"{displayNameValueFromApiInput}\"";  
                SolrQuery solrQuery = new SolrQuery(filter);

 ICollection<string> source = context.CommerceContext.GetObject<ICollection<string>>();

                if (source != null && source.Any<string>())
                    queryOptions.Fields = source;

 SolrQueryResults<Document> solrQueryResults =
 await _searchCommand.QueryDocuments(policy.Name, displayNameValueFromApiInput, queryOptions, context.CommerceContext).ConfigureAwait(false);

 List<Document> documents = new List<Document>(solrQueryResults.Count);

                solrQueryResults.ForEach((Action<Document>)(r =>
                    Document document = new Document();
                    r.Keys.ForEach<string>((Action<string>)(key => document.Add(key, this.ConvertKeyValue(r[key]))));

 // I am picking the entity id of the first found result since in my case the display name was unique

 var sellableItemId= documents.Any() ? Convert.ToString(documents[0]["entityid"]) : null;
 //Get the sellable item once we have the entity id

 ProductArgument productArgument = new ProductArgument(catalogName, sellableItemId);
                SellableItem sellableItem = await _getSellableItemPipeline.Run(productArgument, context).ConfigureAwait(false);	

Here is the method ConvertKeyValue used above. (Taken from dotpeek)

	protected virtual object ConvertKeyValue(object o)
            object obj2;
            if ((obj2 = o) is DateTime)
                o = (object)((DateTime)obj2).ConvertDateTimeToDateTimeOffset(DateTimeKind.Utc);
            return o;