$ npm install @elastic/elasticsearch @nest-up/elastic-client
As a first step import ElasticClientModule
in your root module:
@Module({
imports: [
ElasticClientModule.forRoot({
node: 'http://localhost:9200'
})
]
})
export class AppModule {}
Then define your Document class and decorate it with @ElasticDocment()
decorator:
@ElasticDocument({
indexName: 'products',
type: 'object-settings',
indexOptions: {
settings: {
analysis: {
analyzer: {
custom_analyzer: {
type: 'custom',
tokenizer: 'standard',
filter: ['lowercase']
}
}
}
}
}
})
export class ProductDocument
in the @ElasticDocument()
decorator, you can enter all the configuration options for your index in the form of an object, or provide the path to the.json file with the index configuration if you select json as type:
@ElasticDocument({
indexName: 'products',
type: 'json',
settingsJsonFilePath: './index-mappings/products.index.json'
})
export class ProductDocument {}
In ./index-mappings/products.index.json
{
"indexName": "products",
"type": "object-settings",
"indexOptions": {
"settings": {
"analysis": {
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase"]
}
}
}
}
}
}
Each document may have its own properties, which will be entered in the mappings object in the index. To do that decorate selected properties with @Property()
decorator.
If you do not want to set your own properties - do not use the decorator @Property()
@ElasticDocument({
indexName: 'products',
type: 'object-settings',
createIndexSettings: {
settings: {
analysis: {
analyzer: {
custom_analyzer: {
type: 'custom',
tokenizer: 'standard',
filter: ['lowercase']
}
}
}
}
}
})
export class ProductDocument {
@Property({
type: 'text',
analyzer: 'custom_analyzer'
})
public name: string;
@Property({
type: 'nested',
properties: {
name: {
type: 'text'
}
}
})
public boughtBy: Array<{ name: string }>;
}
You can specify the property configuration as an object or as a path to a configuration file.
export class ProductDocument {
@Property('./propertyMappings/products-index/name-mapping.json')
public name: string;
}
Then define your config in ./propertyMappings/products-index/name-mapping.json
{
"type": "text",
"analyzer": "custom_analyzer"
}
The synchronize option allows the settings in the decorator to be synchronised with the settings of the index. WARNING
This option will change your index settings, so it is highly recommended to deactivate this option on production
@ElasticDocument({
indexName: 'products',
type: 'object-settings',
createOnInit: true,
synchronize: true,
synchronizeSettings: {
settings: {
number_of_replicas: 1,
hidden: true
}
}
})
export class ProductDocument {}
Next register your document in module:
@Module({
imports: [
ElasticClientModule.forFeature({
documents: [ProductDocument]
})
]
})
export class ProductsModule {}
This allows you to inject the document repository in service with @InjectElasticRepository()
decorator
@Injectable()
export class ProductService {
constructor(
@InjectElasticRepository(ProductDocument)
private readonly repo: ElasticRepository<ProductDocument>
) {}
public async findAll() {
return this.repo.findAll();
}
}
1. UseFactory
@Module({
imports: [
ElasticClientModule.forRootAsync({
useFactory: () => {
return {
node: 'http://localhost:9200'
};
}
})
]
})
class AppModule {}
2. Use class
@Injectable()
class ElasticClientConfigService implements ElasticClientOptionsFactory {
createElasticsearchModuleOptions(): ElasticClientFactoryOptions {
return {
node: ['http://localhost:9200']
};
}
}
@Module({
imports: [
ElasticClientModule.forRootAsync({
useClass: ElasticClientConfigService
})
]
})
export class AppModule {}
3. Use existnig
@Module({
imports: [
ElasticClientModule.forRootAsync({
imports: [ConfigModule],
useExisting: ConfigService
})
]
})
class AppModule {}
If you don't want to use repositories - you can inject the elastic client directly into your service
@Injectable()
class ProductSearchService {
constructor(@InjectElasticClient() private readonly client: Client) {}
}
You can create multiple clients, each for a different connection. To do this, register clients in the module:
@Module({
imports: [
ElasticClientModule.forRoot({
node: 'http://localhost:9200'
}),
ElasticClientModule.forRoot({
clientName: 'second-client',
node: 'http://localhost:9300'
})
]
})
class AppModule {}
Once you have created a new client, you can inject it into your service
@Injectable()
export class MyService {
constructor(@InjectElasticClient('second-client') private readonly client: Client) {}
}
To have access the repositories, register your documents, for the relevant client
@Module({
imports: [
ElasticClientModule.forFeature({
documents: [SecondProduct],
clientName: 'second-client'
})
]
})
export class SecondProductsModule {}
You can now inject repositories for a new client
@Injectable()
export class TestService {
constructor(
@InjectElasticRepository(SecondProduct) private repo: ElasticRepository<SecondProduct>
) {}
}
ElasticClientModule allows you to create your own custom repositories. To do so, create your custom repository and decorate it with the @CustomElasticRepository()
decorator
@CustomElasticRepository(ProductDocument)
export class ProductsCustomRepository extends ElasticRepository<ProductDocument> {
public async customOperation() {
return this.client.search({
...// query implementation
})
}
}
After that, register your custom repository in customRepositories section in the ElasticClient:
@Module({
imports: [
ElasticClientModule.forFeature({
documents: [ProductDocument],
customRepositories: [ProductsCustomRepository]
})
]
})
export class ProductsModule {}