Skip to main content

Indexes: Dynamic Fields

While strongly typed entities are well processed by LINQ expressions, some scenarios demand the use of dynamic properties.

To support searching in object graphs they cannot have the entire structure declared upfront.

RavenDB exposes an indexing API for creating fields dynamically.

With this feature, you can search for documents using fields which are created on the fly. For example, consider a Product object that is declared as follows:

public class Product
{
public string Id { get; set; }

// The KEYS under the Attributes object will be dynamically indexed
// Fields added to this object after index creation time will also get indexed
public Dictionary<string, object> Attributes { get; set; }
}

Properties such as color or size are added only to some products, while other ones can have the weight and volume defined. Since Attribute has string fields, they can specify very different properties of products. In order to query on fields which aren't known at index creation time, we introduced the ability to create them dynamically during indexing.

The following index can be created in order to index each attribute value under its name as a separate field:

public class Products_ByAttributeKey : AbstractIndexCreationTask<Product>
{
public Products_ByAttributeKey()
{
Map = products => from p in products
select new
{
// Call 'CreateField' to generate dynamic-index-fields from the Attributes object keys
// Using '_' is just a convention. Any other string can be used instead of '_'

// The actual field name will be item.Key
// The actual field terms will be derived from item.Value
_ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
};
}
}

The _ character used as the field name in the mapping definition is just a convention. You can use any name, it won't be used by the index anyway. The actual field name that you want to query by is defined in CreateField(...). It will generate an index field based on the properties of indexed documents and passed parameters

The index can have more fields defined, just like in any other ordinary index.

Syntax

object CreateField(string name, object value);

object CreateField(string name, object value, bool stored, bool analyzed);

object CreateField(string name, object value, CreateFieldOptions options);
Parameters
namestringName of the dynamic field
valueobjectValue of the dynamic field
storedboolSets FieldStorage. By default value is set to false which equals to FieldStorage.No.
analyzedboolSets FieldIndexing.

Values: null - FieldIndexing.Default (set by overloads without this 'parameter') false - FieldIndexing.Exact true - FieldIndexing.Search | | options | CreateFieldOptions | Dynamic field options |

Options

CreateFieldOptions
StorageFieldStorage?More information about storing data in index can be found here.
IndexingFieldIndexing?More information about analyzers in index can be found here.
TermVectorFieldTermVector?More information about term vectors in index can be found here.

Example

Looking for products by attributes with the usage of such a defined index is supported as if it were real object properties:

IList<Product> results = session
.Query<Products_ByAttribute.Result, Products_ByAttribute>()
.Where(x => x.Color == "Red")
.OfType<Product>()
.ToList();

All types of values are supported by dynamically created fields. They can be numbers, dates, etc.