Indexes: Indexing Polymorphic Data
By default, RavenDB indexes operate only on a specific entity type, or a Collection
, that ignores the inheritance hierarchy.
For example, let's assume that we have the following inheritance hierarchy:

If we saved a Cat
, it would have a collection set to "Cats" and if we saved a Dog
, it would be in collection "Dogs".
If we wanted to index cats by name, we would write:
from cat in docs.Cats
select new { cat.name }
And for dogs:
from dog in docs.Dogs
select new { dog.name }
Although it works, each index would only give us results for the animal it has been defined on. But what if we wanted to query across all animals?
Multi-Map Indexes
The easiest way to do this is by writing a multi-map index like this one:
const indexDefinition = new IndexDefinition();
indexDefinition.name = "Animals/ByName";
indexDefinition.maps = new Set([
"docs.Cats.Select(c => new { name = c.name})",
"docs.Dogs.Select(c => new { name = c.name})"
]);
And query it like this:
const results = await session
.query({ indexName: "Animals/ByName" })
.whereEquals("name", "Mitzy")
.all();
from index 'Animals/ByName'
where name = 'Mitzy'
Other Options
Another option would be to modify the way we generate the Collection for subclasses of Animal
, like this:
{
const store = new DocumentStore();
store.conventions.findCollectionName = clazz => {
if (clazz instanceof Animal) {
return "Animals";
}
return DocumentConventions.defaultGetCollectionName(clazz);
};
}
Using this method, we can now index on all animals using:
from animal in docs.Animals
select new { animal.name }
But what happens when you don't want to modify the entity name of an entity itself?
You can create a polymorphic index using:
from animal in docs.WhereEntityIs("Cats", "Dogs")
select new { animal.Name }
It will generate an index that matches both Cats and Dogs.