Indexes: Dynamic Index 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.
-
In this page:
Indexing documents fields KEYS
Example - index any field under object
The following example allows you to:
- Index any field that is under the some object from the document.
- After index is deployed, any new field added to the this object will be indexed as well.
-
The document:
use Ds\Map as DSMap; class Product { private ?string $id = null; // The KEYS under the Attributes object will be dynamically indexed // Fields added to this object after index creation time will also get indexed public ?DSMap $attributes = null; }
// Sample document content { "Attributes": { "Color": "Red", "Size": 42 } }
-
The index:
The below index will index any field under theAttributes
object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.The actual dynamic-index-field name on which you can query will be the attribute field key.
E.g., KeysColor
&Size
will become the actual dynamic-index-fields.class Products_ByAttributeKey extends AbstractIndexCreationTask { public function __construct() { parent::__construct(); $this->map = "from p in docs.Products select new {" . "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))" . "}"; } }
class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask { public function __construct() { parent::__construct(); $this->setMaps([ "map('Products', function (p) { " . " return { " . " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " . " { indexing: 'Search', storage: false, termVector: null })) " . " }; " . "}) " ]); } }
-
The query:
- You can now query the generated dynamic-index fields.
- To get all documents with some 'size' use:
$matchingDocuments = $session ->advanced() ->documentQuery(Product::class, Products_ByAttributeKey::class) // 'Size' is a dynamic-index-field that was indexed from the Attributes object ->whereEquals("Size", 42) ->toList();
// 'Size' is a dynamic-index-field that was indexed from the Attributes object from index 'Products/ByAttributeKey' where Size = 42
Example - index any field
The following example allows you to:
- Define an index on a collection without needing any common structure between the indexed documents.
- After index is deployed, any new field added to the document will be indexed as well.
Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
-
The document:
class Product { private ?string $id = null; // All KEYS in the document will be dynamically indexed // Fields added to the document after index creation time will also get indexed public ?string $firstName = null; public ?string $lastName = null; public ?string $title = null; // ... getters and setters }
// Sample document content { "FirstName": "John", "LastName": "Doe", "Title": "Engineer", // ... }
-
The index:
The below index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.The actual dynamic-index-field name on which you can query will be the field key.
E.g., KeysFirstName
&LastName
will become the actual dynamic-index-fields.class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask { public function __construct() { parent::__construct(); // This will index EVERY FIELD under the top level of the document $this->setMaps([ "map('Products', function (p) { return { _: Object.keys(p).map(key => createField(key, p[key], { indexing: 'Search', storage: true, termVector: null })) } })" ]); } }
-
The query:
- To get all documents with some 'LastName' use:
$matchingDocuments = $session ->advanced() ->documentQuery(Product::class, Products_ByAnyField_JS::class) // 'LastName' is a dynamic-index-field that was indexed from the document ->whereEquals("LastName", "Doe") ->toList();
// 'LastName' is a dynamic-index-field that was indexed from the document from index 'Products/ByAnyField/JS' where LastName = "Doe"
- To get all documents with some 'LastName' use:
Indexing documents fields VALUES
Example - basic
The following example shows:
- Only the basic concept of creating a dynamic-index-field from the value of a document field.
- Documents can then be queried based on those indexed values.
-
The document:
class Product { public ?string $id = null; // The VALUE of ProductType will be dynamically indexed public ?string $productType = null; public ?int $pricePerUnit = null; // ... getters and setters }
// Sample document content { "ProductType": "Electronics", "PricePerUnit": 23 }
-
The index:
The below index will index the value of document field 'ProductType'.This value will be the dynamic-index-field name on which you can query.
E.g., Field valueElectronics
will be the dynamic-index-field.class Products_ByProductType extends AbstractIndexCreationTask { public function __construct() { parent::__construct(); // Call 'CreateField' to generate the dynamic-index-fields // The field name will be the value of document field 'ProductType' // The field terms will be derived from document field 'PricePerUnit' $this->map = "docs.Products.Select(p => new { " . " _ = this.CreateField(p.productType, p.pricePerUnit) " . "})"; } }
class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask { public function __construct() { parent::__construct(); $this->setMaps([ "map('Products', function (p) { return { _: createField(p.ProductType, p.PricePerUnit, { indexing: 'Search', storage: true, termVector: null }) }; })" ]); } }
-
The query:
- To get all documents of some product type having a specific price per unit use:
$matchingDocuments = $session ->advanced() ->documentQuery(Product::class, Products_ByProductType::class) // 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType' ->whereEquals("Electronics", 23) ->toList();
// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType' from index 'Products/ByProductType' where Electronics = 23
- To get all documents of some product type having a specific price per unit use:
Example - list
The following example allows you to:
- Index values from items in a list
- After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
The document:
class Product { public ?string $id = null; public ?string $name = null; // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields public ?AttributeList $attributes = null; // ... getters and setters } class Attribute { public ?string $propName = null; public ?string $propValue = null; // ... getters and setters } class AttributeList extends TypedList { protected function __construct() { parent::__construct(Attribute::class); } }
// Sample document content { "Name": "SomeName", "Attributes": [ { "PropName": "Color", "PropValue": "Blue" }, { "PropName": "Width", "PropValue": "10" }, { "PropName": "Length", "PropValue": "20" }, ... ] }
-
The index:
The below index will create a dynamic-index-field per item in the document'sAttributes
list.
New items added to the Attributes list after index creation time will be dynamically indexed as well.The actual dynamic-index-field name on which you can query will be the item's PropName value.
E.g., 'PropName' valuewidth
will be a dynamic-index-field.class Attributes_ByName extends AbstractIndexCreationTask { public function __construct() { parent::__construct(); // Define the dynamic-index-fields by calling CreateField // A dynamic-index-field will be generated for each item in the Attributes list // For each item, the field name will be the value of field 'PropName' // The field terms will be derived from field 'PropValue' $this->map = "docs.Products.Select(p => new { " . " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " . " Name = p.name " . "})"; } }
class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask { public function __construct() { parent::__construct(); $this->setMaps([ "map('Products', function (p) { return { _: p.Attributes.map(item => createField(item.PropName, item.PropValue, { indexing: 'Search', storage: true, termVector: null })), Name: p.Name }; })" ]); } }
-
The query:
To get all documents matching a specific attribute property use:/** @var array<Product> $matchingDocuments */ $matchingDocuments = $session ->advanced() ->documentQuery(Product::class, Attributes_ByName::class) // 'Width' is a dynamic-index-field that was indexed from the Attributes list ->whereEquals("Width", 10) ->toList();
// 'Width' is a dynamic-index-field that was indexed from the Attributes list from index 'Attributes/ByName' where Width = 10
CreateField 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-index-field |
value | object |
Value of the dynamic-index-field The field Terms are derived from this value. |
stored | bool |
Sets FieldStorageFalse - will set FieldStorage.NO (default value)True - will set FieldStorate.YES |
analyzed | bool |
Sets FieldIndexingNone - FieldIndexing.Default (default value)False - FieldIndexing.Exact True - FieldIndexing.Search |
options | CreateFieldOptions |
Dynamic-index-field options |
CreateFieldOptions | ||
---|---|---|
Storage | FieldStorage |
Learn about storing data in the index. |
Indexing | FieldIndexing |
|
TermVector | FieldTermVector |
-
All above examples have used the character
_
in the dynamic-index-field definition.
However, using_
is just a convention. Any other string can be used instead. -
This property is Not queryable, it is only used in the index definition syntax.
The actual dynamic-index-fields that are generated are defined by theCreateField
method.
Indexed fields & terms view
The generated dynamic-index-fields and their indexed terms can be viewed in the Terms View.
Below are sample index fields & their terms generated from the last example.

Figure-1: Go to Terms View

Figure-2: Indexed fields & terms