RavenDB version 2.5. Other versions:

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 that cannot have their entire structure be declared upfront, RavenDB exposes the following low-level API for creating fields from within index definitions.

With this feature, you can search for documents even with properties which were created on the fly. For example, consider a Product object that is declared as follows:

    public class Product
    {
    	public string Id { get; set; }
    	public List<Attribute> Attributes { get; set; }
    }
    
    public class Attribute
    {
    	public string Name { get; set; }
    	public string Value { get; set; }
    }
    
    

This way, properties such as color, size, weight and the like are added only to those products which they are indeed valid properties of. However, while they are easily stored, they cannot be easily searched on.

This is where dynamic fields come in. With the following index definition, RavenDB will index the attribute value under the attribute name in its own field:

    public class Product_ByAttribute : AbstractIndexCreationTask<Product>
    {
    	public Product_ByAttribute()
    	{
    		Map = products => from p in products
    						  select new
    									 {
    										 _ = p.Attributes
    											.Select(attribute =>
    												CreateField(attribute.Name, attribute.Value, false, true))
    									 };
    	}
    }
    
    

The underscore used for defining the field name in the Map object is just a convention, you can use any field name instead, but since that we're just want to call the CreateField method and not interesting the field value, we're using _ as a convention to reflect that.

The call to CreateField(...) will generate index fields based on the properties in the provided collection, without creating any field with the name specified there, hence the underscore.

Obviously, this index can have more attributes defined in it for indexing, just like any other ordinary index.

Field options like Store.NO and Index.ANALYZED are configurable also with dynamic fields.

After creating the index, we can easily look for documents using the attribute name as a field to look on, as if it was a real object property. Since it is not really a property, there is no Linq support for it, hence it can only be queried using the LuceneQuery<>() API:

    var products = session.Advanced.LuceneQuery<Product>("Product/ByAttribute")
    	.WhereEquals("Color", "Red")
    	.ToList();
    
    

This will also work for numeric values, so range queries or searches with numeric operators like WhereGreaterThan() will work as well.

Comments add new comment

The comments section is for user feedback or community content. If you seek assistance or have any questions, please post them at our support forums.

Ade
REPLY Posted by Ade on

Is it possible to have a dynamic field index use anything other than the default analyzer? For instance, how would I specify that I wanted to use the SimpleAnalyzer for my dynamic field index?

Oren Eini
REPLY Posted by Oren Eini on

Yes, if you know what the names are. If you don't know the name, you can use an AbstractAnalyzerGenerator to decide what analyzer a dynamic field will use.

Joe
REPLY Posted by Joe on

Do you have an example of how to use an AbstractAnalyzerGenerator to change the default analyzer for a dynamic field index? There is not much online about this topic. Thanks!

Ayende Rahien
REPLY Posted by Ayende Rahien on

It is pretty simple:

  • You create a class derived from AbstractAnalyzerGenerator,
  • You compile the dll and drop it in the Plugins directory.
  • You are done.

When writing the AbstractAnalyzerGenerator derived class, you can use the provided parameters (index name, the document to be indexed, the query) to decide what analyzer to return.

Søren Spelling Lund
REPLY Posted by Søren Spelling Lund on

Is it possible to convert an advanced query back to LINQ to perform additional filtering based on the strongly typed entity in the index with dynamic fields?

Søren Spelling Lund
REPLY Posted by Søren Spelling Lund on

Also I'd like to be able to do ToFacets after the fact :)

Yong Liang
REPLY Posted by Yong Liang on

Hi, does the RavenQuery support the dynamic linq?

SUBMIT COMMENT