docs: handle product status change in MeiliSearch and Algolia guides (#14141)
* docs: handle product status change in MeiliSearch and Algolia guides * added missing status field
This commit is contained in:
@@ -403,15 +403,21 @@ The workflow has the following steps:
|
||||
{
|
||||
type: "step",
|
||||
name: "syncProductsStep",
|
||||
description: "Index products in Algolia.",
|
||||
depth: 1
|
||||
description: "Index published products in Algolia.",
|
||||
depth: 2
|
||||
},
|
||||
{
|
||||
type: "step",
|
||||
name: "deleteProductsFromAlgoliaStep",
|
||||
description: "Delete unpublished products from Algolia.",
|
||||
depth: 3
|
||||
}
|
||||
]
|
||||
}}
|
||||
hideLegend
|
||||
/>
|
||||
|
||||
Medusa provides the `useQueryGraphStep` in its `@medusajs/medusa/core-flows` package. So, you only need to implement the second step.
|
||||
Medusa provides the `useQueryGraphStep` in its `@medusajs/medusa/core-flows` package. So, you only need to implement the other steps.
|
||||
|
||||
### syncProductsStep
|
||||
|
||||
@@ -533,6 +539,64 @@ The compensation function receives two parameters:
|
||||
|
||||
In the compensation function, you resolve the Algolia Module's service from the container. Then, you delete from Algolia the products that were newly indexed, and revert the existing products to their original data.
|
||||
|
||||
#### deleteProductsFromAlgoliaStep
|
||||
|
||||
The `deleteProductsFromAlgoliaStep` step deletes products from Algolia by their IDs.
|
||||
|
||||
Create the step at `src/workflows/steps/delete-products-from-algolia.ts` with the following content:
|
||||
|
||||
```ts title="src/workflows/steps/delete-products-from-algolia.ts"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { ALGOLIA_MODULE } from "../../modules/algolia"
|
||||
|
||||
export type DeleteProductsFromAlgoliaWorkflow = {
|
||||
ids: string[]
|
||||
}
|
||||
|
||||
export const deleteProductsFromAlgoliaStep = createStep(
|
||||
"delete-products-from-algolia-step",
|
||||
async (
|
||||
{ ids }: DeleteProductsFromAlgoliaWorkflow,
|
||||
{ container }
|
||||
) => {
|
||||
const algoliaModuleService = container.resolve(ALGOLIA_MODULE)
|
||||
|
||||
const existingRecords = await algoliaModuleService.retrieveFromIndex(
|
||||
ids,
|
||||
"product"
|
||||
)
|
||||
await algoliaModuleService.deleteFromIndex(
|
||||
ids,
|
||||
"product"
|
||||
)
|
||||
|
||||
return new StepResponse(undefined, existingRecords)
|
||||
},
|
||||
async (existingRecords, { container }) => {
|
||||
if (!existingRecords) {
|
||||
return
|
||||
}
|
||||
const algoliaModuleService = container.resolve(ALGOLIA_MODULE)
|
||||
|
||||
await algoliaModuleService.indexData(
|
||||
existingRecords as unknown as Record<string, unknown>[],
|
||||
"product"
|
||||
)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
The step receives the IDs of the products to delete as an input.
|
||||
|
||||
In the step, you resolve the Algolia Module's service and retrieve the existing records from Algolia. This is useful to revert the deletion if an error occurs.
|
||||
|
||||
Then, you delete the products from Algolia and pass the existing records to the compensation function.
|
||||
|
||||
In the compensation function, you reindex the existing records if an error occurs.
|
||||
|
||||
### Add Sync Products Workflow
|
||||
|
||||
You can now create the workflow that syncs the products to Algolia.
|
||||
@@ -547,7 +611,7 @@ import {
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
|
||||
import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products"
|
||||
import { ProductStatus } from "@medusajs/framework/utils"
|
||||
import { deleteProductsFromAlgoliaStep } from "./steps/delete-products-from-algolia"
|
||||
|
||||
type SyncProductsWorkflowInput = {
|
||||
filters?: Record<string, unknown>
|
||||
@@ -558,15 +622,7 @@ type SyncProductsWorkflowInput = {
|
||||
export const syncProductsWorkflow = createWorkflow(
|
||||
"sync-products",
|
||||
({ filters, limit, offset }: SyncProductsWorkflowInput) => {
|
||||
const productFilters = transform({
|
||||
filters,
|
||||
}, (data) => {
|
||||
return {
|
||||
status: ProductStatus.PUBLISHED,
|
||||
...data.filters,
|
||||
}
|
||||
})
|
||||
const { data, metadata } = useQueryGraphStep({
|
||||
const { data: products, metadata } = useQueryGraphStep({
|
||||
entity: "product",
|
||||
fields: [
|
||||
"id",
|
||||
@@ -579,20 +635,49 @@ export const syncProductsWorkflow = createWorkflow(
|
||||
"categories.handle",
|
||||
"tags.id",
|
||||
"tags.value",
|
||||
"status",
|
||||
],
|
||||
pagination: {
|
||||
take: limit,
|
||||
skip: offset,
|
||||
},
|
||||
filters: productFilters,
|
||||
filters,
|
||||
})
|
||||
|
||||
const {
|
||||
publishedProducts,
|
||||
unpublishedProductsToDelete,
|
||||
} = transform({
|
||||
products,
|
||||
}, (data) => {
|
||||
const publishedProducts: SyncProductsStepInput["products"] = []
|
||||
const unpublishedProductsToDelete: string[] = []
|
||||
|
||||
data.products.forEach((product) => {
|
||||
if (product.status === "published") {
|
||||
const { status, ...rest } = product
|
||||
publishedProducts.push(rest as SyncProductsStepInput["products"][0])
|
||||
} else {
|
||||
unpublishedProductsToDelete.push(product.id)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
publishedProducts,
|
||||
unpublishedProductsToDelete,
|
||||
}
|
||||
})
|
||||
|
||||
syncProductsStep({
|
||||
products: data,
|
||||
} as SyncProductsStepInput)
|
||||
products: publishedProducts,
|
||||
})
|
||||
|
||||
deleteProductsFromAlgoliaStep({
|
||||
ids: unpublishedProductsToDelete,
|
||||
})
|
||||
|
||||
return new WorkflowResponse({
|
||||
products: data,
|
||||
products,
|
||||
metadata,
|
||||
})
|
||||
}
|
||||
@@ -606,7 +691,9 @@ It accepts as a second parameter a constructor function, which is the workflow's
|
||||
In the workflow's constructor function, you:
|
||||
|
||||
1. Execute `useQueryGraphStep` to retrieve products from Medusa's database. This step uses Medusa's [Query](!docs!/learn/fundamentals/module-links/query) tool to retrieve data across modules. You pass it the pagination and filter parameters you received in the input.
|
||||
2. Execute `syncProductsStep` to index the products in Algolia. You pass it the products you retrieved in the previous step.
|
||||
2. Use [transform](!docs!/learn/fundamentals/workflows/variable-manipulation) to prepare two lists: one for published products to index in Algolia and another for unpublished products to delete from Algolia.
|
||||
2. Execute `syncProductsStep` to index the published products in Algolia.
|
||||
3. Execute `deleteProductsFromAlgoliaStep` to delete unpublished products from Algolia.
|
||||
|
||||
A workflow must return an instance of `WorkflowResponse`. The `WorkflowResponse` constructor accepts the workflow's output as a parameter, which is an object holding the retrieved products and their pagination details.
|
||||
|
||||
@@ -908,7 +995,6 @@ export default async function handleProductEvents({
|
||||
input: {
|
||||
filters: {
|
||||
id: data.id,
|
||||
status: "published",
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -939,67 +1025,11 @@ Then, either create a product or update an existing one using the Medusa Admin d
|
||||
|
||||
When a product is deleted, you need to remove it from the Algolia index. As this requires a different action than creating or updating a product, you'll create a new workflow that deletes the product from Algolia, then create a subscriber that listens to the `product.deleted` event to trigger the workflow.
|
||||
|
||||
#### Create Delete Product Step
|
||||
|
||||
The workflow to delete a product from Algolia will have only one step that deletes products by their IDs from Algolia.
|
||||
|
||||
So, create the step at `src/workflows/steps/delete-products-from-algolia.ts` with the following content:
|
||||
|
||||
```ts title="src/workflows/steps/delete-products-from-algolia.ts"
|
||||
import {
|
||||
createStep,
|
||||
StepResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { ALGOLIA_MODULE } from "../../modules/algolia"
|
||||
|
||||
export type DeleteProductsFromAlgoliaWorkflow = {
|
||||
ids: string[]
|
||||
}
|
||||
|
||||
export const deleteProductsFromAlgoliaStep = createStep(
|
||||
"delete-products-from-algolia-step",
|
||||
async (
|
||||
{ ids }: DeleteProductsFromAlgoliaWorkflow,
|
||||
{ container }
|
||||
) => {
|
||||
const algoliaModuleService = container.resolve(ALGOLIA_MODULE)
|
||||
|
||||
const existingRecords = await algoliaModuleService.retrieveFromIndex(
|
||||
ids,
|
||||
"product"
|
||||
)
|
||||
await algoliaModuleService.deleteFromIndex(
|
||||
ids,
|
||||
"product"
|
||||
)
|
||||
|
||||
return new StepResponse(undefined, existingRecords)
|
||||
},
|
||||
async (existingRecords, { container }) => {
|
||||
if (!existingRecords) {
|
||||
return
|
||||
}
|
||||
const algoliaModuleService = container.resolve(ALGOLIA_MODULE)
|
||||
|
||||
await algoliaModuleService.indexData(
|
||||
existingRecords as unknown as Record<string, unknown>[],
|
||||
"product"
|
||||
)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
The step receives the IDs of the products to delete as an input.
|
||||
|
||||
In the step, you resolve the Algolia Module's service and retrieve the existing records from Algolia. This is useful to revert the deletion if an error occurs.
|
||||
|
||||
Then, you delete the products from Algolia and pass the existing records to the compensation function.
|
||||
|
||||
In the compensation function, you reindex the existing records if an error occurs.
|
||||
|
||||
#### Create Delete Product Workflow
|
||||
|
||||
You can now create the workflow that deletes products from Algolia. Create the file `src/workflows/delete-products-from-algolia.ts` with the following content:
|
||||
You've already created the `deleteProductsFromAlgoliaStep` that deletes products from Algolia by their IDs. So, you can create the workflow that uses this step.
|
||||
|
||||
Create the file `src/workflows/delete-products-from-algolia.ts` with the following content:
|
||||
|
||||
```ts title="src/workflows/delete-products-from-algolia.ts"
|
||||
import { createWorkflow } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
Reference in New Issue
Block a user