Indexing Metadata


  • Each document in the database includes a metadata section, stored in a special JSON object under the @metadata property.

  • This metadata is not part of the document's content but holds internal system information (used by RavenDB), such as the document ID, collection name, change vector, last modified timestamp, and more,
    as well as optional user-defined entries.

  • To learn how to access (get and modify) the metadata from your client code,
    see How to get and modify the metadata.

  • Content from metadata properties can be extracted and indexed within a static index, alongside content from the document fields. This allows you to query for documents based on values stored in the metadata.
    See the examples below.



Indexing metadata properties

  • Use the MetadataFor method to access a document's metadata within the index definition,
    as shown in the example below.

  • You can retrieve metadata values using one of two syntaxes:

    • Generic method syntax
      Use Value<T>() to retrieve and cast the metadata value to the expected type.
      This is type-safe and preferred when the type is known (e.g., DateTime).
    • Indexer syntax
      Use metadata["key"] to retrieve the raw object.
      You can cast it manually if needed.

  • The following index definition indexes content from the @last-modified and @counters metadata properties.

public class Products_ByMetadata_AccessViaValue : AbstractIndexCreationTask<Product>
{
    public class IndexEntry
    {
        public DateTime LastModified { get; set; }
        public bool HasCounters { get; set; }
    }

    public Products_ByMetadata_AccessViaValue()
    {
        Map = products => from product in products
            // Use 'MetadataFor' to access the metadata object
            let metadata = MetadataFor(product)
            
            // Define the index fields
            select new IndexEntry()
            {
                // Access metadata properties using generic method
                LastModified = metadata.Value<DateTime>(
                    // Specify the Client API Constant corresponding to '@last-modified'
                    Raven.Client.Constants.Documents.Metadata.LastModified),
                
                HasCounters =  metadata.Value<object>(
                    // Specify the Client API Constant corresponding to '@counters'
                    Raven.Client.Constants.Documents.Metadata.Counters) != null
            };
    }
}
public class Products_ByMetadata_AccessViaIndexer : AbstractIndexCreationTask<Product>
{
    public class IndexEntry
    {
        public DateTime LastModified { get; set; }
        public bool HasCounters { get; set; }
    }

    public Products_ByMetadata_AccessViaIndexer()
    {
        Map = products => from product in products
            // Use 'MetadataFor' to access the metadata object
            let metadata = MetadataFor(product)
            
            // Define the index fields
            select new IndexEntry()
            {
                // Access metadata properties using indexer
                LastModified =
                    // Specify the Client API Constant corresponding to '@last-modified'
                    (DateTime)metadata[Raven.Client.Constants.Documents.Metadata.LastModified],

                HasCounters = 
                    // Specify the Client API Constant corresponding to '@counters'
                    metadata[Raven.Client.Constants.Documents.Metadata.Counters] != null
            };
    }
}
public class Products_ByMetadata_JS : AbstractJavaScriptIndexCreationTask
{
    public Products_ByMetadata_JS()
    {
        Maps = new HashSet<string>
        {
            @"map('Products', function (product) {
                var metadata = metadataFor(product);

                return {
                    LastModified: metadata['@last-modified'],
                    HasCounters: !!metadata['@counters']
                };
            })"
        };
    }
}
  • Query for documents based on metadata values:
    Retrieve documents that have counters and order them by their last modified timestamp.

List<Product> productsWithCounters = session
    .Query<Products_ByMetadata_AccessViaValue.IndexEntry,
        Products_ByMetadata_AccessViaValue>()
    .Where(x => x.HasCounters == true)
    .OrderByDescending(x => x.LastModified)
    .OfType<Product>()
    .ToList();
List<Product> productsWithCounters = await asyncSession
    .Query<Products_ByMetadata_AccessViaValue.IndexEntry,
        Products_ByMetadata_AccessViaValue>()
    .Where(x => x.HasCounters == true)
    .OrderByDescending(x => x.LastModified)
    .OfType<Product>()
    .ToListAsync();
List<Product> productsWithCounters = session.Advanced.
    DocumentQuery<Products_ByMetadata_AccessViaValue.IndexEntry,
        Products_ByMetadata_AccessViaValue>()
    .WhereEquals(x => x.HasCounters, true)
    .OrderByDescending(x => x.LastModified)
    .OfType<Product>()
    .ToList();
from index "Products/ByMetadata/AccessViaValue"
where HasCounters == true
order by LastModified desc

Metadata properties that can be indexed

  • The table below lists predefined metadata properties that can be indexed.

  • Each property can be accessed using either a string literal (e.g. "@last-modified") or the corresponding Client API constant (e.g. Raven.Client.Constants.Documents.Metadata.LastModified).
    Using the Client API constant is recommended for clarity and to avoid typos.

  • You can add custom metadata properties to any document as needed.
    These custom properties can be indexed just like the predefined ones.

String literal Client API Constant
@archive-at Raven.Client.Constants.Documents.Metadata.ArchiveAt
@attachments Raven.Client.Constants.Documents.Metadata.Attachments
@change-vector Raven.Client.Constants.Documents.Metadata.ChangeVector
@collection Raven.Client.Constants.Documents.Metadata.Collection
@counters Raven.Client.Constants.Documents.Metadata.Counters
@etag Raven.Client.Constants.Documents.Metadata.Etag
@expires Raven.Client.Constants.Documents.Metadata.Expires
@id Raven.Client.Constants.Documents.Metadata.Id
@last-modified Raven.Client.Constants.Documents.Metadata.LastModified
@refresh Raven.Client.Constants.Documents.Metadata.Refresh
@timeseries Raven.Client.Constants.Documents.Metadata.TimeSeries
Raven-Clr-Type Raven.Client.Constants.Documents.Metadata.RavenClrType

Note:

  • The @attachments metadata property can only be indexed using a Lucene index.
  • The Corax search engine does not support indexing complex JSON properties.
    Learn more in Corax: Handling complex JSON objects.