Indexes: Dynamic Fields
-
In RavenDB different documents can have different shapes.
Documents are schemaless - new fields can be added or removed as needed. -
For such dynamic data, you can define indexes with dynamic-index-fields.
-
This allows querying the index on fields that aren't yet known at index creation time,
which is very useful when working on highly dynamic systems. -
Any value type can be indexed, string, number, date, etc.
-
An index definition can contain both dynamic-index-fields and regular-index-fields.
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 static class Product {
private String id;
private List<Attribute> attributes;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Attribute> getAttributes() {
return attributes;
}
public void setAttributes(List<Attribute> attributes) {
this.attributes = attributes;
}
}
public static class Attribute {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
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 static class Products_ByAttribute extends AbstractIndexCreationTask {
public Products_ByAttribute() {
map = "docs.Products.Select(p => new { " +
" _ = p.Attributes.Select(attribute => this.CreateField(attribute.name, attribute.value, false, true)) " +
"})";
}
}
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 | ||
---|---|---|
name | String |
Name of the dynamic field |
value | Object |
Value of the dynamic field |
stored | boolean |
Sets FieldStorage. By default value is set to false which equals to FieldStorage.No . |
analyzed | boolean |
Sets FieldIndexing. Values: null - FieldIndexing.Default (set by overloads without this 'parameter')false - FieldIndexing.Exact true - FieldIndexing.Search |
options | CreateFieldOptions |
Dynamic field options |
Options
CreateFieldOptions | ||
---|---|---|
Storage | FieldStorage |
More information about storing data in index can be found here. |
Indexing | FieldIndexing |
More information about analyzers in index can be found here. |
TermVector | FieldTermVector |
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:
List<Product> results = session
.query(Product.class, Products_ByAttribute.class)
.whereEquals("color", "red")
.toList();
Information
All types of values are supported by dynamically created fields. They can be numbers, dates, etc.