Sometimes we need to create a custom crawler in our solution in order to add custom items in our solr index that are not part of our Sitecore instance, for example, read an external API and add those results in the index.
Ok, reading the API is the easy part of this, so let’s talk about how to add a custom document to our index.
Follow these steps
Get your index instance
using (var solr = ContentSearchManager.GetIndex("desired_index_name"))
Get your template definition using your template’s ID
var template = contextDb.GetTemplate("{9843569E-C37A-434B-942B-92DBAACEC619}");
Now, why I’m using a Sitecore template? Since I’m using the Sitecore Content Search Library, these methods assume that I’m adding a Sitecore item, so, which means that I need to simulate the creation of a Sitecore item, but, without creating the item in the database.
The reason is that we need to overwrite some properties for Sitecore.Data.Items.Item class. The properties that we need to overwrite are the following:
- Parent
- ParentID
- Paths
About the Paths property, since is another class, we need to overwrite some method properties as well in order to save our custom item in solr, the properties are:
- ContentPath
- FullPath
- LongID
If you want to make sure although it is not mandatory, you need to overwrite the following methods:
- GetPath(ItemPathType type)
- GetPath(string from, string separator, ItemPathType type)
So here is an example of those custom classes with the overridden properties and methods
CustomItem class
public class CustomItem : Item
{
public EventBaseItem(ID itemID, ItemData data, Database database) : base(itemID, data, database)
{
}
public override Item Parent {
get {
var contextDb = Database.GetDatabase("web");
//modify the path as needed
return contextDb.GetItem("/sitecore/content/web-site/home");
}
}
public override ID ParentID => this.Parent.ParentID;
public override ItemPath Paths {
get {
return new CustomtItemPath(this);
}
}
}
CustomItemPath class
public class CustomtItemPath : ItemPath
{
public override string ContentPath
{
get {
return $"/sitecore/content/web-site/home/{Item.Name}";
}
}
public override string FullPath {
get {
return $"/sitecore/content/web-site/home/{Item.Name}";
}
}
public override string LongID {
get {
return "/{11111111-1111-1111-1111-111111111111}/{desired_id_of_parent}/" + Item.ID.ToString();
}
}
public EventItemPath(Item item) : base(item)
{
}
protected EventItemPath(Item item, BaseItemManager itemManager, BaseCacheManager cacheManager) : base(item, itemManager, cacheManager)
{
}
public override string GetPath(ItemPathType type)
{
return base.GetPath(ItemPathType.Name);
}
public override string GetPath(string from, string separator, ItemPathType type)
{
return base.GetPath("/sitecore", separator, ItemPathType.Name);
}
}
So, getting back to item creation the next step, create the new document that will be added to Solr.
Basically, we need to add all instances of base classes that compose a Sitecore Item, so take a look at the code below:
var ItemId = ID.NewID;
ItemDefinition definition = new ItemDefinition(ItemId, "Item Name", template.ID, ID.NewID);
ItemData itemData = new ItemData(definition, Language.Current, Sitecore.Data.Version.First, fields);
CustomItem item = new CustomItem(ItemId, itemData, contextDb);
Here I’m adding the Id, the name the language, and so on, then let’s create the item:
item.Editing.BeginEdit();
item["event_id"] = externalContentItem.Id;
item["event_title"] = externalContentItem.Title;
item["event_description"] = externalContentItem.Description;
item["event_location"] = externalContentItem.Location;
item["event_start_date_unix"] = externalContentItem.DateStartUnix;
item["event_end_date_unix"] = externalContentItem.DateEndUnix;
item["event_custom_data"] = externalContentItem.CustomData;
item["event_rrule"] = externalContentItem.Rrule;
item.Editing.EndEdit();
And finally, let’s save the item in Solr:
using (new SecurityDisabler())
{
var searchItem = new SitecoreIndexableItem(item);
var ctx = solr.CreateUpdateContext();
solr.Operations.Add(searchItem, ctx, solr.Configuration);
ctx.Commit();
}
When you run the “Add” method, you have to keep in mind that if you have computed fields for your index, those ones will be executed.
And that is it, you have your custom document in Solr.
Here you can find the complete code of the example:
public void IndexEventsInSolr(List<ExternalDataInfo> externalItems)
{
var contextDb = Database.GetDatabase("web");
var solr = SitecoreUtils.GetSearchIndex(contextDb);
FieldList fields = new FieldList();
var template = contextDb.GetTemplate("{9843569E-C37A-434B-942B-92DBAACEC619}");
foreach (var externalContentItem in externalItems)
{
var ItemId = ID.NewID;
ItemDefinition definition = new ItemDefinition(ItemId,"Item Name", template.ID, ID.NewID);
ItemData itemData = new ItemData(definition, Language.Current, Sitecore.Data.Version.First, fields);
CustomItem item = new CustomItem (ItemId, itemData, contextDb);
item.Editing.BeginEdit();
item["event_id"] = externalContentItem.Id;
item["event_title"] = externalContentItem.Title;
item["event_description"] = externalContentItem.Description;
item["event_location"] = externalContentItem.Location;
item["event_start_date_unix"] = externalContentItem.DateStartUnix;
item["event_end_date_unix"] = externalContentItem.DateEndUnix;
item["event_custom_data"] = externalContentItem.CustomData;
item["event_rrule"] = externalContentItem.Rrule;
item.Editing.EndEdit();
using (new SecurityDisabler())
{
var searchItem = new SitecoreIndexableItem(item);
var ctx = solr.CreateUpdateContext();
solr.Operations.Add(searchItem, ctx, solr.Configuration);
ctx.Commit();
}
}
}