Multi-Map Indexes
-
Multi-Map indexes allow you to index data from multiple collections, like polymorphic data or any data common to different types.
-
Learn how to index polymorphic data
Learn how to create Multi-Map-Reduce indexes -
In this page:
Indexing multiple collections
Let's assume that we have Dog
and Cat
classes, both inheriting from the class Animal
:
class Dog extends Animal { }
class Cat extends Animal { }
class Animal {
constructor(name) {
this.name = name;
}
}
Now we can define and query our index as follows:
class Animals_ByName extends AbstractJavaScriptMultiMapIndexCreationTask {
constructor() {
super();
// Index field 'name' from the Cats collection
this.map('Cats', cat => {
return {
name: cat.name
};
});
// Index field 'name' from the Dogs collection
this.map('Dogs', dog => {
return {
name: dog.name
};
});
}
}
const results = await session
// Query the index
.query({ indexName: "Animals/ByName" })
// Look for all animals (either a cat or a dog) that are named 'Mitzy' :)
.whereEquals("name", "Mitzy")
.all();
from index "Animals/ByName"
where Name == "Mitzy"
Searching across multiple collections
Another great usage of Multi-Map indexes is smart-search.
To search for products, companies, or employees by their name, you need to define the following index:
class Smart_Search extends AbstractJavaScriptMultiMapIndexCreationTask {
constructor() {
super();
this.map('Companies', company => {
return {
id: id(company),
content: company.Name,
displayName: company.Name,
collection: this.getMetadata(company)["@collection"]
};
});
this.map('Products', product => {
return {
id: id(product),
content: product.Name,
displayName: product.Name,
collection: this.getMetadata(product)["@collection"]
};
});
this.map('Employees', employee => {
return {
id: id(employee),
content: [employee.FirstName, employee.LastName],
displayName: employee.FirstName + " " + employee.LastName,
collection: this.getMetadata(employee)["@collection"]
};
});
// Mark the 'content' field with 'Search' to enable full-text search queries
this.index("content", "Search");
// Store fields in index so that when projecting these fields from the query
// the data will come from the index, and not from the storage.
this.store("id", "Yes");
this.store("collection", "Yes");
this.store("displayName", "Yes");
}
}
and query it using:
const results = await session
.query({ indexName: "Smart/Search" })
// Search across all indexed collections
.search("content", "Lau*")
// Project results
.selectFields([ "id", "displayName", "collection" ])
.all();
// Results:
// ========
for (const result of results) {
console.log(result.collection + ": " + result.displayName);
// Companies: Laughing Bacchus Wine Cellars
// Products: Laughing Lumberjack Lager
// Employees: Laura Callahan
}
from index "Smart/Search"
where search(content, "Lau*")
select id() as id, displayName, collection
Remarks
Remember that all map functions must output objects
with an identical shape (the field names have to match).