When A Custom Facet Is Extended, Mongo Is Not Immediately Affected
Just because Mongo isn't showing the added facet/element/attribute, doesn't mean that the Facet isn't there. MongoDB will only store Facet information if there is information to store. By adding an element to the Contact Facet model, that does not automatically update MongoDB directly.
The only way for MongoDB to update directly is to update the contact record, save a value to the new facet element/attribute, and then flush to xDB or release the contact.
A Lot of Background Information
Extending Existing OOTB Facets
You can not extend the Existing OOTB Facets because the Concrete Classes that represent them are protected (internal). You would have to recreate the concrete class from scratch.
using Sitecore.Analytics.Model.Entities;
using Sitecore.Analytics.Model.Framework;
using System;
namespace Sitecore.Analytics.Model.Generated
{
[Serializable]
internal class ContactEmailAddresses : Facet, IContactEmailAddresses, IFacet, IElement, IValidatable
{
private const string PREFERRED = "Preferred";
private const string ENTRIES = "Entries";
public IElementDictionary<IEmailAddress> Entries
{
get
{
return this.GetDictionary<IEmailAddress>("Entries");
}
}
public string Preferred
{
get
{
return this.GetAttribute<string>("Preferred");
}
set
{
this.SetAttribute<string>("Preferred", value);
}
}
public ContactEmailAddresses()
{
this.EnsureAttribute<string>("Preferred");
this.EnsureDictionary<IEmailAddress>("Entries");
}
}
}
To achieve this instead, you'd want to make a whole new facet model. To validate how you have created your custom contact facet, see below for an example on how I do it.
In the example below, I've called that Marketing Data.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<model>
<elements>
<element interface="SitecoreHacker.Sandbox.Facets.IMarketingData, SitecoreHacker.Sandbox"
implementation="SitecoreHacker.Sandbox.Facets.MarketingData, SitecoreHacker.Sandbox"/>
</elements>
<entities>
<contact>
<facets>
<facet name="Marketing Data" contract="SitecoreHacker.Sandbox.Facets.IMarketingData, SitecoreHacker.Sandbox"/>
</facets>
</contact>
</entities>
</model>
</sitecore>
</configuration>
Step 1: Gather information about the facet
Create a custom facet is actually not that difficult. What’s more difficult, IMHO, is obtaining what kind of information you want in your facet? Getting the following stuff together before you start coding will allow you not break your coding groove.
- The name of the Facet.
- What information do you want to capture?
- Name of field
- Type of field (strings, GUID, integrers, and floats.
Step 2: Create the element contract that defines the facet
By creating a facet, what we’re really doing is creating the root element interface that will contain all of the other structures going into our facet. We will define our interface inheriting from IFacet.
using Sitecore.Analytics.Model.Framework;
namespace SitecoreHacker.Sandbox.Facets
{
public interface IMarketingData : IFacet
{
string CustomerId { get; set; }
string Segment { get; set; }
}
}
Here I have defined an interface called IMarketingData that is based on the IFacet interface. There are two things I want to capture in this IFacet: CustomerId and Segment. Both of these values are strings.
That was easy, right?
Step 3: Create the implementation of your element contract
Now I want to create the concrete class that can implement the interface that we just created.
using System;
using Sitecore.Analytics.Model.Framework;
namespace SitecoreHacker.Sandbox.Facets
{
[Serializable]
public class MarketingData: Facet, IMarketingData
{
private const string CUSTOMER_ID = "CustomerId";
private const string SEGEMENT = "Segment";
#region Properties
public string CustomerId
{
get { return GetAttribute<string>(CUSTOMER_ID); }
set { SetAttribute(CUSTOMER_ID, value); }
}
public string Segment
{
get { return GetAttribute<string>(SEGEMENT); }
set { SetAttribute(SEGEMENT, value); }
}
#endregion
public MarketingData()
{
EnsureAttribute<string>(CUSTOMER_ID);
EnsureAttribute<string>(SEGEMENT);
}
}
}
Alright, there’s a little bit more going on here so let’s step through it.
First, just create a class and base it off of Facet and IMarketingData
We base off of Facet because this is our root Element. If we were just creating an Element that would be used in this Facet, and in addition to the Facet Element, then we would have a base class of Element More on that later.
Add the [Serializable] attribute.
This would seem unimportant, but becomes super important depending on the type of Session State being run. So just use it. Don’t ask questions. =)
Now the implementation class has three parts as follows.
Don’t implement any other functions in this class outside of the following:
- Constants
- For every attribute that you have, define a constant that will provide a label for that attribute.
- Protip: I found out the hard way that the constants defined, the value must equal the actual name of the class property for the same attribute.
- Class Properties
- For every attribute, create getters and setters.
- Important: Name the Property the same as the value of the constant that you set for it.
- For Getters:
return GetAttribute<type>(string name);
- Type of your attribute: string, Guid, Integers, or Float name: Reference the constant variable defined for your attribute.
- For Setters
SetAttribute<type>(string name, value);
- Type of your attribute: string, Guid, Integers, or Float
name: Reference the constant variable defined for your attribute.
- Class Constructor
- No parameters
- Call
EnsureAttribute<string>(string name);
for each attribute.
Save and compile! Now, you'll want to run something that saves information to that Facet. As long as there is actual data to save to the Facet, Mongo will store it.

Step 1: Create The Element Contract
We start off by creating an interface for our new Element. Using this example, we create the “IProduct” interface with two property attributes: Product Name, and Product Price.
If you recall from ealier, Elements plug into the Facet, and a Facet is and of itself an Element as well as a collection of Elements.
using Sitecore.Analytics.Model.Framework;
namespace SitecoreHacker.Sandbox.Facets
{
public interface IProduct : IElement
{
string ProductName { get; set; }
string ProductPrice { get; set; }
}
}
Simple interface deriving from the IElement interface. Now we need to create our concrete class that will support this interface. We will call this the “Product” class.
Step 2: Create The Element Concrete Class
using System;
using Sitecore.Analytics.Model.Framework;
namespace SitecoreHacker.Sandbox.Facets
{
[Serializable]
public class Product : Element, IProduct
{
private const string PRODUCT_NAME = "ProductName";
private const string PRODUCT_PRICE = "ProductPrice";
public string ProductName
{
get { return GetAttribute<string>(PRODUCT_NAME); }
set { SetAttribute(PRODUCT_NAME, value); }
}
public string ProductPrice
{
get { return GetAttribute<string>(PRODUCT_PRICE); }
set { SetAttribute(PRODUCT_PRICE, value); }
}
public Product()
{
EnsureAttribute<string>(PRODUCT_NAME);
EnsureAttribute<string>(PRODUCT_PRICE);
}
}
}
You’ll note that this is a pretty straight forward class.
Here we have setup the ProductName and ProductPrice property elements for a single Product Element. This is the single object representation for the collection objects that our Facet (“Marketing Data”) is going to reference.
Step 3: Add Element Dictionary to our Parent Element Interface
In this case, our parent element is our class based off of the IFacet contract. I call this out because you can nest elements within elements, but that’s outside the scope of this blog. We’ll reopen our IMarketingData contract and add the Element Dictionary Property.
using Sitecore.Analytics.Model.Framework;
namespace SitecoreHacker.Sandbox.Facets
{
public interface IMarketingData : IFacet
{
string CustomerId { get; set; }
string Segment { get; set; }
IElementDictionary<IProduct> Products { get; }
}
}
Note here that IElementDictionary Products {get;} is the property attribute that we added to the IMarketingDara Facet. IElementDictionary is the class that Sitecore uses to refer to a collection of like Elements. In this case, our like Element is the IProduct type.
Step 4: Add Element Dictionary to our Parent Element Class
We’ve finished updating our interface, now we need to update the concrete class representing our parent element/facet and implement the IElementDictionary property.
using System;
using Sitecore.Analytics.Model.Framework;
namespace SitecoreHacker.Sandbox.Facets
{
[Serializable]
public class MarketingData: Facet, IMarketingData
{
private const string CUSTOMER_ID = "CustomerId";
private const string SEGEMENT = "Segment";
private const string PRODUCTS = "Products";
#region Properties
public string CustomerId
{
get { return GetAttribute<string>(CUSTOMER_ID); }
set { SetAttribute(CUSTOMER_ID, value); }
}
public string Segment
{
get { return GetAttribute<string>(SEGEMENT); }
set { SetAttribute(SEGEMENT, value); }
}
public IElementDictionary<IProduct> Products
{
get { return GetDictionary<IProduct>(PRODUCTS); }
}
#endregion
public MarketingData()
{
EnsureAttribute<string>(CUSTOMER_ID);
EnsureAttribute<string>(SEGEMENT);
EnsureDictionary<IProduct>(PRODUCTS);
}
}
}
Stepping through this we do the same three steps for every property in an element:
- We’ve added our constant string variable which contacts the text name of our dictionary property.
- Implemented the Property based on the contract.
- In the constructor, we’ve Ensured that the Dictionary is loaded.
Step 5: Patch New Element to Model Configuration
Finally, we just need to add our Element to the Element collection for the Contact model in the Sitecore configuration.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<model>
<elements>
<element interface="SitecoreHacker.Sandbox.Facets.IMarketingData, SitecoreHacker.Sandbox"
implementation="SitecoreHacker.Sandbox.Facets.MarketingData, SitecoreHacker.Sandbox"/>
<element interface="SitecoreHacker.Sandbox.Facets.IProduct, SitecoreHacker.Sandbox"
implementation="SitecoreHacker.Sandbox.Facets.Product, SitecoreHacker.Sandbox"/>
</elements>
<entities>
<contact>
<facets>
<facet name="Marketing Data" contract="SitecoreHacker.Sandbox.Facets.IMarketingData, SitecoreHacker.Sandbox"/>
</facets>
</contact>
</entities>
</model>
</sitecore>
</configuration>
We have now extended our already custom Facet, and added an additional Element collection (ElementDictionary) to hold additional information.
Now you'll want to make sure that you save a contact with information for the extended facet. If you've followed these instructions, then Mongo will show you something similar to the below contact:

Additional Information About Uploading Contacts with Custom Facets
Depending on how you create new Contacts... could have an effect on existing contact facet data. If you use the CSV import, you should be aware that as of 8.2 Update 2, there is still a bug in Sitecore's List Manager that will remove custom facet information for an existing contact, if said contact Identifier is uploaded via CSV. I don't think that is your problem, but if it is, or you have the scenario, let me know, and I'll provide additional information.