|
|
@@ -30,7 +30,7 @@ import {
|
|
|
import { Observable } from 'rxjs';
|
|
|
import { In, IsNull } from 'typeorm';
|
|
|
|
|
|
-import { ELASTIC_SEARCH_OPTIONS, loggerCtx, VARIANT_INDEX_NAME } from '../constants';
|
|
|
+import { ELASTIC_SEARCH_OPTIONS, VARIANT_INDEX_NAME, loggerCtx } from '../constants';
|
|
|
import { ElasticsearchOptions } from '../options';
|
|
|
import {
|
|
|
BulkOperation,
|
|
|
@@ -49,9 +49,6 @@ import {
|
|
|
|
|
|
import { createIndices, getClient, getIndexNameByAlias } from './indexing-utils';
|
|
|
|
|
|
-const REINDEX_CHUNK_SIZE = 2500;
|
|
|
-const REINDEX_OPERATION_CHUNK_SIZE = 3000;
|
|
|
-
|
|
|
export const defaultProductRelations: Array<EntityRelationPaths<Product>> = [
|
|
|
'featuredAsset',
|
|
|
'facetValues',
|
|
|
@@ -129,11 +126,7 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
* Updates the search index only for the affected product.
|
|
|
*/
|
|
|
async deleteProduct({ ctx: rawContext, productId }: UpdateProductMessageData): Promise<boolean> {
|
|
|
- const operations = await this.deleteProductOperations(
|
|
|
- RequestContext.deserialize(rawContext),
|
|
|
- productId,
|
|
|
- );
|
|
|
- await this.executeBulkOperations(operations);
|
|
|
+ await this.deleteProductOperations(RequestContext.deserialize(rawContext), productId);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -244,9 +237,9 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
const ctx = MutableRequestContext.deserialize(rawContext);
|
|
|
|
|
|
const reindexTempName = new Date().getTime();
|
|
|
- const variantIndexName = this.options.indexPrefix + VARIANT_INDEX_NAME;
|
|
|
- const variantIndexNameForReindex = VARIANT_INDEX_NAME + `-reindex-${reindexTempName}`;
|
|
|
- const reindexVariantAliasName = this.options.indexPrefix + variantIndexNameForReindex;
|
|
|
+ const variantIndexName = `${this.options.indexPrefix}${VARIANT_INDEX_NAME}`;
|
|
|
+ const variantIndexNameForReindex = `${VARIANT_INDEX_NAME}-reindex-${reindexTempName}`;
|
|
|
+ const reindexVariantAliasName = `${this.options.indexPrefix}${variantIndexNameForReindex}`;
|
|
|
try {
|
|
|
await createIndices(
|
|
|
this.client,
|
|
|
@@ -262,7 +255,7 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
throw e;
|
|
|
}
|
|
|
|
|
|
- const totalProductIds = await this.connection
|
|
|
+ const totalProductIds = await this.connection.rawConnection
|
|
|
.getRepository(Product)
|
|
|
.createQueryBuilder('product')
|
|
|
.where('product.deletedAt IS NULL')
|
|
|
@@ -274,19 +267,17 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
let skip = 0;
|
|
|
let finishedProductsCount = 0;
|
|
|
do {
|
|
|
- const operations: BulkVariantOperation[] = [];
|
|
|
-
|
|
|
- productIds = await this.connection
|
|
|
+ productIds = await this.connection.rawConnection
|
|
|
.getRepository(Product)
|
|
|
.createQueryBuilder('product')
|
|
|
.select('product.id')
|
|
|
.where('product.deletedAt IS NULL')
|
|
|
.skip(skip)
|
|
|
- .take(REINDEX_CHUNK_SIZE)
|
|
|
+ .take(this.options.reindexProductsChunkSize)
|
|
|
.getMany();
|
|
|
|
|
|
for (const { id: productId } of productIds) {
|
|
|
- operations.push(...(await this.updateProductsOperationsOnly(ctx, productId)));
|
|
|
+ await this.updateProductsOperationsOnly(ctx, productId, variantIndexNameForReindex);
|
|
|
finishedProductsCount++;
|
|
|
observer.next({
|
|
|
total: totalProductIds,
|
|
|
@@ -295,98 +286,13 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- Logger.verbose(`Will execute ${operations.length} bulk update operations`, loggerCtx);
|
|
|
-
|
|
|
- // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
- await this.executeBulkOperationsByChunks(
|
|
|
- REINDEX_OPERATION_CHUNK_SIZE,
|
|
|
- operations,
|
|
|
- variantIndexNameForReindex,
|
|
|
- );
|
|
|
-
|
|
|
- skip += REINDEX_CHUNK_SIZE;
|
|
|
+ skip += this.options.reindexProductsChunkSize;
|
|
|
|
|
|
Logger.verbose(`Done ${finishedProductsCount} / ${totalProductIds} products`);
|
|
|
- } while (productIds.length >= REINDEX_CHUNK_SIZE);
|
|
|
+ } while (productIds.length >= this.options.reindexProductsChunkSize);
|
|
|
|
|
|
// Switch the index to the new reindexed one
|
|
|
- try {
|
|
|
- const reindexVariantAliasExist = await this.client.indices.existsAlias({
|
|
|
- name: reindexVariantAliasName,
|
|
|
- });
|
|
|
- if (reindexVariantAliasExist) {
|
|
|
- const reindexVariantIndexName = await getIndexNameByAlias(
|
|
|
- this.client,
|
|
|
- reindexVariantAliasName,
|
|
|
- );
|
|
|
- const originalVariantAliasExist = await this.client.indices.existsAlias({
|
|
|
- name: variantIndexName,
|
|
|
- });
|
|
|
- const originalVariantIndexExist = await this.client.indices.exists({
|
|
|
- index: variantIndexName,
|
|
|
- });
|
|
|
-
|
|
|
- const originalVariantIndexName = await getIndexNameByAlias(
|
|
|
- this.client,
|
|
|
- variantIndexName,
|
|
|
- );
|
|
|
-
|
|
|
- const actions = [
|
|
|
- {
|
|
|
- remove: {
|
|
|
- index: reindexVariantIndexName,
|
|
|
- alias: reindexVariantAliasName,
|
|
|
- },
|
|
|
- },
|
|
|
- {
|
|
|
- add: {
|
|
|
- index: reindexVariantIndexName,
|
|
|
- alias: variantIndexName,
|
|
|
- },
|
|
|
- },
|
|
|
- ];
|
|
|
-
|
|
|
- if (originalVariantAliasExist.body) {
|
|
|
- actions.push({
|
|
|
- remove: {
|
|
|
- index: originalVariantIndexName,
|
|
|
- alias: variantIndexName,
|
|
|
- },
|
|
|
- });
|
|
|
- } else if (originalVariantIndexExist.body) {
|
|
|
- await this.client.indices.delete({
|
|
|
- index: [variantIndexName],
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- await this.client.indices.updateAliases({
|
|
|
- body: {
|
|
|
- actions,
|
|
|
- },
|
|
|
- });
|
|
|
-
|
|
|
- if (originalVariantAliasExist.body) {
|
|
|
- await this.client.indices.delete({
|
|
|
- index: [originalVariantIndexName],
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (e: any) {
|
|
|
- Logger.error('Could not switch indexes');
|
|
|
- } finally {
|
|
|
- const reindexVariantAliasExist = await this.client.indices.existsAlias({
|
|
|
- name: reindexVariantAliasName,
|
|
|
- });
|
|
|
- if (reindexVariantAliasExist.body) {
|
|
|
- const reindexVariantAliasResult = await this.client.indices.getAlias({
|
|
|
- name: reindexVariantAliasName,
|
|
|
- });
|
|
|
- const reindexVariantIndexName = Object.keys(reindexVariantAliasResult.body)[0];
|
|
|
- await this.client.indices.delete({
|
|
|
- index: [reindexVariantIndexName],
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
+ await this.switchAlias(reindexVariantAliasName, variantIndexName);
|
|
|
|
|
|
Logger.verbose('Completed reindexing!', loggerCtx);
|
|
|
|
|
|
@@ -404,6 +310,10 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
operations: BulkVariantOperation[],
|
|
|
index = VARIANT_INDEX_NAME,
|
|
|
): Promise<void> {
|
|
|
+ Logger.verbose(
|
|
|
+ `Will execute ${operations.length} bulk update operations with index ${index}`,
|
|
|
+ loggerCtx,
|
|
|
+ );
|
|
|
let i;
|
|
|
let j;
|
|
|
let processedOperation = 0;
|
|
|
@@ -499,61 +409,146 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
}
|
|
|
|
|
|
private async updateProductsInternal(ctx: MutableRequestContext, productIds: ID[]) {
|
|
|
- const operations = await this.updateProductsOperations(ctx, productIds);
|
|
|
- await this.executeBulkOperations(operations);
|
|
|
+ await this.updateProductsOperations(ctx, productIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ private async switchAlias(reindexVariantAliasName: string, variantIndexName: string): Promise<void> {
|
|
|
+ try {
|
|
|
+ const reindexVariantAliasExist = await this.client.indices.existsAlias({
|
|
|
+ name: reindexVariantAliasName,
|
|
|
+ });
|
|
|
+ if (reindexVariantAliasExist) {
|
|
|
+ const reindexVariantIndexName = await getIndexNameByAlias(
|
|
|
+ this.client,
|
|
|
+ reindexVariantAliasName,
|
|
|
+ );
|
|
|
+ const originalVariantAliasExist = await this.client.indices.existsAlias({
|
|
|
+ name: variantIndexName,
|
|
|
+ });
|
|
|
+ const originalVariantIndexExist = await this.client.indices.exists({
|
|
|
+ index: variantIndexName,
|
|
|
+ });
|
|
|
+
|
|
|
+ const originalVariantIndexName = await getIndexNameByAlias(this.client, variantIndexName);
|
|
|
+
|
|
|
+ const actions = [
|
|
|
+ {
|
|
|
+ remove: {
|
|
|
+ index: reindexVariantIndexName,
|
|
|
+ alias: reindexVariantAliasName,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ add: {
|
|
|
+ index: reindexVariantIndexName,
|
|
|
+ alias: variantIndexName,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ if (originalVariantAliasExist.body) {
|
|
|
+ actions.push({
|
|
|
+ remove: {
|
|
|
+ index: originalVariantIndexName,
|
|
|
+ alias: variantIndexName,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else if (originalVariantIndexExist.body) {
|
|
|
+ await this.client.indices.delete({
|
|
|
+ index: [variantIndexName],
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ await this.client.indices.updateAliases({
|
|
|
+ body: {
|
|
|
+ actions,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ if (originalVariantAliasExist.body) {
|
|
|
+ await this.client.indices.delete({
|
|
|
+ index: [originalVariantIndexName],
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e: any) {
|
|
|
+ Logger.error('Could not switch indexes');
|
|
|
+ } finally {
|
|
|
+ const reindexVariantAliasExist = await this.client.indices.existsAlias({
|
|
|
+ name: reindexVariantAliasName,
|
|
|
+ });
|
|
|
+ if (reindexVariantAliasExist.body) {
|
|
|
+ const reindexVariantAliasResult = await this.client.indices.getAlias({
|
|
|
+ name: reindexVariantAliasName,
|
|
|
+ });
|
|
|
+ const reindexVariantIndexName = Object.keys(reindexVariantAliasResult.body)[0];
|
|
|
+ await this.client.indices.delete({
|
|
|
+ index: [reindexVariantIndexName],
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private async updateProductsOperationsOnly(
|
|
|
ctx: MutableRequestContext,
|
|
|
productId: ID,
|
|
|
- ): Promise<BulkVariantOperation[]> {
|
|
|
- const operations: BulkVariantOperation[] = [];
|
|
|
+ index = VARIANT_INDEX_NAME,
|
|
|
+ ): Promise<void> {
|
|
|
+ let operations: BulkVariantOperation[] = [];
|
|
|
let product: Product | undefined;
|
|
|
try {
|
|
|
product = await this.connection
|
|
|
- .getRepository(Product)
|
|
|
- .findOne({
|
|
|
+ .getRepository(ctx, Product)
|
|
|
+ .find({
|
|
|
where: { id: productId, deletedAt: IsNull() },
|
|
|
relations: this.productRelations,
|
|
|
})
|
|
|
- .then(result => result ?? undefined);
|
|
|
+ .then(result => result[0] ?? undefined);
|
|
|
} catch (e: any) {
|
|
|
Logger.error(e.message, loggerCtx, e.stack);
|
|
|
throw e;
|
|
|
}
|
|
|
if (!product) {
|
|
|
- return operations;
|
|
|
+ return;
|
|
|
}
|
|
|
- const updatedProductVariants = await this.connection.getRepository(ProductVariant).find({
|
|
|
- relations: this.variantRelations,
|
|
|
- where: {
|
|
|
- productId,
|
|
|
- deletedAt: IsNull(),
|
|
|
- },
|
|
|
- order: {
|
|
|
- id: 'ASC',
|
|
|
- },
|
|
|
- });
|
|
|
+
|
|
|
+ let updatedProductVariants: ProductVariant[] = [];
|
|
|
+ try {
|
|
|
+ updatedProductVariants = await this.connection.rawConnection.getRepository(ProductVariant).find({
|
|
|
+ relations: this.variantRelations,
|
|
|
+ where: {
|
|
|
+ productId,
|
|
|
+ deletedAt: IsNull(),
|
|
|
+ },
|
|
|
+ order: {
|
|
|
+ id: 'ASC',
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } catch (e: any) {
|
|
|
+ Logger.error(e.message, loggerCtx, e.stack);
|
|
|
+ }
|
|
|
+
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
updatedProductVariants.forEach(variant => (variant.product = product!));
|
|
|
if (!product.enabled) {
|
|
|
updatedProductVariants.forEach(v => (v.enabled = false));
|
|
|
}
|
|
|
+
|
|
|
Logger.debug(`Updating Product (${productId})`, loggerCtx);
|
|
|
const languageVariants: LanguageCode[] = [];
|
|
|
languageVariants.push(...product.translations.map(t => t.languageCode));
|
|
|
- for (const variant of updatedProductVariants) {
|
|
|
+ for (const variant of updatedProductVariants)
|
|
|
languageVariants.push(...variant.translations.map(t => t.languageCode));
|
|
|
- }
|
|
|
+
|
|
|
const uniqueLanguageVariants = unique(languageVariants);
|
|
|
for (const channel of product.channels) {
|
|
|
ctx.setChannel(channel);
|
|
|
const variantsInChannel = updatedProductVariants.filter(v =>
|
|
|
v.channels.map(c => c.id).includes(ctx.channelId),
|
|
|
);
|
|
|
- for (const variant of variantsInChannel) {
|
|
|
+ for (const variant of variantsInChannel)
|
|
|
await this.productPriceApplicator.applyChannelPriceAndTax(variant, ctx);
|
|
|
- }
|
|
|
+
|
|
|
for (const languageCode of uniqueLanguageVariants) {
|
|
|
if (variantsInChannel.length) {
|
|
|
for (const variant of variantsInChannel) {
|
|
|
@@ -583,6 +578,16 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
},
|
|
|
},
|
|
|
);
|
|
|
+
|
|
|
+ if (operations.length >= this.options.reindexBulkOperationSizeLimit) {
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+ operations = [];
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
operations.push(
|
|
|
@@ -607,24 +612,35 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
},
|
|
|
);
|
|
|
}
|
|
|
+ if (operations.length >= this.options.reindexBulkOperationSizeLimit) {
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+ operations = [];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return operations;
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- private async updateProductsOperations(
|
|
|
- ctx: MutableRequestContext,
|
|
|
- productIds: ID[],
|
|
|
- ): Promise<BulkVariantOperation[]> {
|
|
|
+ private async updateProductsOperations(ctx: MutableRequestContext, productIds: ID[]): Promise<void> {
|
|
|
Logger.debug(`Updating ${productIds.length} Products`, loggerCtx);
|
|
|
- const operations: BulkVariantOperation[] = [];
|
|
|
-
|
|
|
for (const productId of productIds) {
|
|
|
- operations.push(...(await this.deleteProductOperations(ctx, productId)));
|
|
|
- operations.push(...(await this.updateProductsOperationsOnly(ctx, productId)));
|
|
|
+ await this.deleteProductOperations(ctx, productId);
|
|
|
+ await this.updateProductsOperationsOnly(ctx, productId);
|
|
|
}
|
|
|
- return operations;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -645,7 +661,7 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
for (const relation of hydratedRelations) {
|
|
|
let path = relation.split('.');
|
|
|
if (path[0] === 'customFields') {
|
|
|
- if (2 < path.length) {
|
|
|
+ if (path.length > 2) {
|
|
|
throw new InternalServerError(
|
|
|
[
|
|
|
'hydrateProductRelations / hydrateProductVariantRelations does not currently support nested custom field relations',
|
|
|
@@ -670,9 +686,10 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
private async deleteProductOperations(
|
|
|
ctx: RequestContext,
|
|
|
productId: ID,
|
|
|
- ): Promise<BulkVariantOperation[]> {
|
|
|
+ index: string = VARIANT_INDEX_NAME,
|
|
|
+ ): Promise<void> {
|
|
|
const channels = await this.requestContextCache.get(ctx, 'elastic-index-all-channels', () =>
|
|
|
- this.connection
|
|
|
+ this.connection.rawConnection
|
|
|
.getRepository(Channel)
|
|
|
.createQueryBuilder('channel')
|
|
|
.select('channel.id')
|
|
|
@@ -696,17 +713,15 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
.andWhere('channel.id = :channelId', { channelId: ctx.channelId })
|
|
|
.getOne();
|
|
|
|
|
|
- if (!product) {
|
|
|
- return [];
|
|
|
- }
|
|
|
+ if (!product) return;
|
|
|
|
|
|
Logger.debug(`Deleting 1 Product (id: ${productId})`, loggerCtx);
|
|
|
- const operations: BulkVariantOperation[] = [];
|
|
|
+ let operations: BulkVariantOperation[] = [];
|
|
|
const languageVariants: LanguageCode[] = [];
|
|
|
languageVariants.push(...product.translations.map(t => t.languageCode));
|
|
|
- for (const variant of product.variants) {
|
|
|
+ for (const variant of product.variants)
|
|
|
languageVariants.push(...variant.translations.map(t => t.languageCode));
|
|
|
- }
|
|
|
+
|
|
|
const uniqueLanguageVariants = unique(languageVariants);
|
|
|
|
|
|
for (const { id: channelId } of channels) {
|
|
|
@@ -719,25 +734,42 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
+ if (operations.length >= this.options.reindexBulkOperationSizeLimit) {
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+ operations = [];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- operations.push(
|
|
|
- ...(await this.deleteVariantsInternalOperations(
|
|
|
- product.variants,
|
|
|
- channels.map(c => c.id),
|
|
|
- uniqueLanguageVariants,
|
|
|
- )),
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+
|
|
|
+ await this.deleteVariantsInternalOperations(
|
|
|
+ product.variants,
|
|
|
+ channels.map(c => c.id),
|
|
|
+ uniqueLanguageVariants,
|
|
|
+ index,
|
|
|
);
|
|
|
- return operations;
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
private async deleteVariantsInternalOperations(
|
|
|
variants: ProductVariant[],
|
|
|
channelIds: ID[],
|
|
|
languageVariants: LanguageCode[],
|
|
|
- ): Promise<BulkVariantOperation[]> {
|
|
|
+ index = VARIANT_INDEX_NAME,
|
|
|
+ ): Promise<void> {
|
|
|
Logger.debug(`Deleting ${variants.length} ProductVariants`, loggerCtx);
|
|
|
- const operations: BulkVariantOperation[] = [];
|
|
|
+ let operations: BulkVariantOperation[] = [];
|
|
|
for (const variant of variants) {
|
|
|
for (const channelId of channelIds) {
|
|
|
for (const languageCode of languageVariants) {
|
|
|
@@ -753,10 +785,25 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
+ if (operations.length >= this.options.reindexBulkOperationSizeLimit) {
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+ operations = [];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return operations;
|
|
|
+ // Because we can have a huge amount of variant for 1 product, we also chunk update operations
|
|
|
+ await this.executeBulkOperationsByChunks(
|
|
|
+ this.options.reindexBulkOperationSizeLimit,
|
|
|
+ operations,
|
|
|
+ index,
|
|
|
+ );
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
private async getProductIdsByVariantIds(variantIds: ID[]): Promise<ID[]> {
|