Click or drag to resize
Working with JSON Attributes

With the release of version 2.1.1, Sphinx introduced a new attribute type for storing JSON objects. As of version 3.2 SphinxConnector.NET supports these attributes by leveraging the well-known JSON.NET library (currently at version 4.5).

Note Note
In case you are using an older Sphinx version: when working with JSON attributes, please bear in mind that there were some limititions on the Sphinx side before 2.2.1, e.g. no support for multi-level JSON objects and arrays can only hold strings.
Using JSON attributes

To use JSON attributes in your document models, you need to first create an object that represents the JSON attribute and than add a property for that type to your document model. By default, SphinxConnector.NET will treat every type as a JSON attribute that can not be stored in one of the other attributes types by Sphinx, i.e. primitive types like int, enums, strings, DateTime, or a generic enumerable with a numeric type.

Handling of DateTime Objects

Due to the lack of a date type in JSON, there are currently several different formats used for storing date information, but none is generally accepted. As SphinxConnector.NET internally uses JSON.NET to serialize JSON objects, its default setting which is to serialize dates according to the ISO 8601 standard e.g." 2013-01-07T07:22Z", is used.

Example: Using a Dictionary for Dynamic Properties

JSON attributes can come in handy if a document has different properties depending on the context. A possible example would be a product in an eCommerce application that apart form common attributes like name and price, has additional information depending on the product type. One possible way to handle such a scenario is to use a dictionary that holds these additional properties and is stored in a JSON attribute:

Document Model
public class Product    
{
    public Product()
    {
        Properties = new Dictionary<string, object>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }

    public IDictionary<string, object> Properties { get; set; }
}
RT-Index Configuration for Product
index products
{
        type                                = rt
        path                                = products

        rt_field                        = name
        rt_field                        = description
        rt_attr_string      = name
        rt_attr_string      = description
        rt_attr_float       = price 
        rt_attr_json                = properties        
}

The following code shows an example where we have two products with different attributes:

C#
Product firstProduct = new Product
                      {
                          Id = 1,
                          Name = "First Product",
                          Description = "First Product Description",
                          Price = 9.99m
                      };

firstProduct.Properties.Add("Length", 5);
firstProduct.Properties.Add("Height", 10);
firstProduct.Properties.Add("Width", 20);
firstProduct.Properties.Add("Material", "Wood");

Product secondProduct = new Product
                            {
                                Id = 2,
                                Name = "Second Product",
                                Description = "Second Product Description",
                                Price = 19.99m
                            };

firstProduct.Properties.Add("OS", "Windows 8");
firstProduct.Properties.Add("Weight", 2.4);
firstProduct.Properties.Add("Resolution", "1600x1200");

session.Save(new[] { firstProduct, secondProduct });

They can also be used in Where, OrderBy, etc.

C#
var result = session.Query<Product>().
                     Where(x => (string)x.Properties["OS"] == "Windows 8" && (int)x.Properties["Weight"] < 3).
                     ToList();
Working with Any/All/IndexOf

Sphinx requires ANY(), ALL() and INDEXOF() to be in the SELECT() clause of a SphinxQL statement. The same is true for the fluent API.

Example: Our index contains products along with their manuals in different languages. As we don't to search the manuals, but still display them, we add them as a JSON attribute:

Document Model
public class Product    
{
    public Product()
    {
        Properties = new List<string, object>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }

    public IList<Manual> Manuals { get; set; }
}

public class Manual
{
    public string Language { get; set; }

    public string Content { get; set; }
}
Retrieving only products with an english manual:
var result = session.Query<Product>().
                     Match("a product search").
                     Select(p=> new 
                     {
                         Product = p,
                         HasEnglishManual = p.Manuals.Any(m => m.Language == "EN").
                     })
                     Where(x => x.HasEnglishManual).
                     ToList();
Note Note
Note how we specify our condition in the Select() method and add a filter to the Where() clause.

This also applies to LEAST(), GREATEST() and LENGTH(). To use these functions you have to call the Min(), Max() and Any() extension methods on a collection that holds JSON data.