adjustments
rename search subscriber fix: comments in medusa-interfaces/search-service.js add: use cursor pagination when indexing all products to search engine fix: emit product_id on product-variant creation fix: move search API route under products/search fix: use meilisearchService instead of searchService in plugin loader
This commit is contained in:
1 parent
1444353b0a
commit
3a10e37377
9 files changed
+68
-63
No files matched your search
@@ -11,8 +11,8 @@ class SearchService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to create an index
|
* Used to create an index
|
||||||
* @param indexName {string} - the index name.
|
* @param indexName {string} - the index name
|
||||||
* @param [options] {string} - the index name.
|
* @param [options] {string} - the index name
|
||||||
* @return {Promise<{object}>} - returns response from search engine provider
|
* @return {Promise<{object}>} - returns response from search engine provider
|
||||||
*/
|
*/
|
||||||
createIndex(indexName, options) {
|
createIndex(indexName, options) {
|
||||||
@@ -29,8 +29,8 @@ class SearchService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to index documents by the search engine provider.
|
* Used to index documents by the search engine provider
|
||||||
* @param indexName {string} - the index name.
|
* @param indexName {string} - the index name
|
||||||
* @param documents {Array.<Object>} - documents array to be indexed
|
* @param documents {Array.<Object>} - documents array to be indexed
|
||||||
* @return {Promise<{object}>} - returns response from search engine provider
|
* @return {Promise<{object}>} - returns response from search engine provider
|
||||||
*/
|
*/
|
||||||
@@ -50,8 +50,8 @@ class SearchService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to delete document
|
* Used to delete document
|
||||||
* @param indexName {string} - the index name.
|
* @param indexName {string} - the index name
|
||||||
* @param document_id {string} - the id of the document.
|
* @param document_id {string} - the id of the document
|
||||||
* @return {Promise<{object}>} - returns response from search engine provider
|
* @return {Promise<{object}>} - returns response from search engine provider
|
||||||
*/
|
*/
|
||||||
deleteDocument(indexName, document_id) {
|
deleteDocument(indexName, document_id) {
|
||||||
@@ -60,7 +60,7 @@ class SearchService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to delete all documents
|
* Used to delete all documents
|
||||||
* @param indexName {string} - the index name.
|
* @param indexName {string} - the index name
|
||||||
* @return {Promise<{object}>} - returns response from search engine provider
|
* @return {Promise<{object}>} - returns response from search engine provider
|
||||||
*/
|
*/
|
||||||
deleteAllDocuments(indexName) {
|
deleteAllDocuments(indexName) {
|
||||||
@@ -69,10 +69,10 @@ class SearchService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to search for a document in an index
|
* Used to search for a document in an index
|
||||||
* @param indexName {string} - the index name.
|
* @param indexName {string} - the index name
|
||||||
* @param query {string} - the search query.
|
* @param query {string} - the search query
|
||||||
* @param options {object} - any options passed to the request object other than the query and indexName
|
* @param options {object} - any options passed to the request object other than the query and indexName
|
||||||
* e.g. pagination options, filtering options, etc.
|
* e.g. pagination options, filtering options, etc
|
||||||
* @return {Promise<{object}>} - returns response from search engine provider
|
* @return {Promise<{object}>} - returns response from search engine provider
|
||||||
*/
|
*/
|
||||||
search(indexName, query, options) {
|
search(indexName, query, options) {
|
||||||
@@ -81,7 +81,7 @@ class SearchService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to update the settings of an index
|
* Used to update the settings of an index
|
||||||
* @param indexName {string} - the index name.
|
* @param indexName {string} - the index name
|
||||||
* @param settings {object} - settings object
|
* @param settings {object} - settings object
|
||||||
* @return {Promise<{object}>} - returns response from search engine provider
|
* @return {Promise<{object}>} - returns response from search engine provider
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ const INDEX_NS = "medusa-commerce"
|
|||||||
|
|
||||||
export default async (container, options) => {
|
export default async (container, options) => {
|
||||||
try {
|
try {
|
||||||
const searchService = container.resolve("searchService")
|
const meilisearchService = container.resolve("meilisearchService")
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.entries(options.settings).map(([key, value]) =>
|
Object.entries(options.settings).map(([key, value]) =>
|
||||||
searchService.updateSettings(`${INDEX_NS}_${key}`, value)
|
meilisearchService.updateSettings(`${INDEX_NS}_${key}`, value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import returnReasonRoutes from "./return-reasons"
|
|||||||
import swapRoutes from "./swaps"
|
import swapRoutes from "./swaps"
|
||||||
import variantRoutes from "./variants"
|
import variantRoutes from "./variants"
|
||||||
import giftCardRoutes from "./gift-cards"
|
import giftCardRoutes from "./gift-cards"
|
||||||
import searchRoutes from "./search"
|
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ export default (app, container, config) => {
|
|||||||
returnRoutes(route)
|
returnRoutes(route)
|
||||||
giftCardRoutes(route)
|
giftCardRoutes(route)
|
||||||
returnReasonRoutes(route)
|
returnReasonRoutes(route)
|
||||||
searchRoutes(route)
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ export default app => {
|
|||||||
app.use("/products", route)
|
app.use("/products", route)
|
||||||
|
|
||||||
route.get("/", middlewares.wrap(require("./list-products").default))
|
route.get("/", middlewares.wrap(require("./list-products").default))
|
||||||
|
route.post("/search", middlewares.wrap(require("./search").default))
|
||||||
route.get("/:id", middlewares.wrap(require("./get-product").default))
|
route.get("/:id", middlewares.wrap(require("./get-product").default))
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
+2
-3
@@ -1,11 +1,10 @@
|
|||||||
import { Validator, MedusaError } from "medusa-core-utils"
|
import { Validator, MedusaError } from "medusa-core-utils"
|
||||||
import { INDEX_NS } from "../../../../utils/index-ns"
|
import ProductService from "../../../../services/product"
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const schema = Validator.object()
|
const schema = Validator.object()
|
||||||
.keys({
|
.keys({
|
||||||
q: Validator.string().required(),
|
q: Validator.string().required(),
|
||||||
indexName: Validator.string().required(),
|
|
||||||
})
|
})
|
||||||
.options({ allowUnknown: true })
|
.options({ allowUnknown: true })
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ export default async (req, res) => {
|
|||||||
const searchService = req.scope.resolve("searchService")
|
const searchService = req.scope.resolve("searchService")
|
||||||
|
|
||||||
const results = await searchService.search(
|
const results = await searchService.search(
|
||||||
`${INDEX_NS}_${indexName}`,
|
ProductService.IndexName,
|
||||||
q,
|
q,
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { Router } from "express"
|
|
||||||
import middlewares from "../../../middlewares"
|
|
||||||
|
|
||||||
const route = Router()
|
|
||||||
|
|
||||||
export default app => {
|
|
||||||
app.use("/search", route)
|
|
||||||
|
|
||||||
route.post("/", middlewares.wrap(require("./search").default))
|
|
||||||
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
@@ -203,6 +203,7 @@ class ProductVariantService extends BaseService {
|
|||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.emit(ProductVariantService.Events.CREATED, {
|
.emit(ProductVariantService.Events.CREATED, {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
|
product_id: result.product_id,
|
||||||
})
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -749,41 +749,59 @@ class ProductService extends BaseService {
|
|||||||
return product
|
return product
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all products into the search engine
|
||||||
|
*/
|
||||||
|
|
||||||
async loadIntoSearchEngine() {
|
async loadIntoSearchEngine() {
|
||||||
if (this.searchService_.isDefault) return
|
if (this.searchService_.isDefault) return
|
||||||
|
|
||||||
const products = await this.list(
|
const TAKE = 20
|
||||||
{},
|
const totalCount = await this.count()
|
||||||
{
|
let iterCount = 0,
|
||||||
select: [
|
lastSeenId = ""
|
||||||
"id",
|
|
||||||
"title",
|
|
||||||
"subtitle",
|
|
||||||
"description",
|
|
||||||
"handle",
|
|
||||||
"is_giftcard",
|
|
||||||
"discountable",
|
|
||||||
"thumbnail",
|
|
||||||
"profile_id",
|
|
||||||
"collection_id",
|
|
||||||
"type_id",
|
|
||||||
"origin_country",
|
|
||||||
"created_at",
|
|
||||||
"updated_at",
|
|
||||||
],
|
|
||||||
relations: ["variants", "tags", "type", "collection"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const flattenSkus = product => {
|
|
||||||
product.sku = flattenField(product.variants, "sku").filter(Boolean)
|
|
||||||
return product
|
|
||||||
}
|
|
||||||
const productsWithSkus = products.map(product => flattenSkus(product))
|
|
||||||
|
|
||||||
await this.searchService_.addDocuments(
|
while (iterCount < totalCount) {
|
||||||
ProductService.IndexName,
|
console.log({ lastSeenId })
|
||||||
productsWithSkus
|
const products = await this.list(
|
||||||
)
|
{ id: { gte: lastSeenId } },
|
||||||
|
{
|
||||||
|
select: [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"subtitle",
|
||||||
|
"description",
|
||||||
|
"handle",
|
||||||
|
"is_giftcard",
|
||||||
|
"discountable",
|
||||||
|
"thumbnail",
|
||||||
|
"profile_id",
|
||||||
|
"collection_id",
|
||||||
|
"type_id",
|
||||||
|
"origin_country",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
],
|
||||||
|
relations: ["variants", "tags", "type", "collection"],
|
||||||
|
take: TAKE,
|
||||||
|
order: { id: "ASC" },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const flattenSkus = product => {
|
||||||
|
product.sku = flattenField(product.variants, "sku").filter(Boolean)
|
||||||
|
return product
|
||||||
|
}
|
||||||
|
|
||||||
|
const productsWithSkus = products.map(product => flattenSkus(product))
|
||||||
|
|
||||||
|
await this.searchService_.addDocuments(
|
||||||
|
ProductService.IndexName,
|
||||||
|
productsWithSkus
|
||||||
|
)
|
||||||
|
|
||||||
|
iterCount += TAKE
|
||||||
|
lastSeenId = products.at(-1).id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ import ProductService from "../services/product"
|
|||||||
import ProductVariantService from "../services/product-variant"
|
import ProductVariantService from "../services/product-variant"
|
||||||
import { flattenField } from "../utils/flatten-field"
|
import { flattenField } from "../utils/flatten-field"
|
||||||
|
|
||||||
class SearchSubscriber {
|
class ProductSearchSubscriber {
|
||||||
constructor({ eventBusService, searchService, productService }, options) {
|
constructor({ eventBusService, searchService, productService }, options) {
|
||||||
this.eventBus_ = eventBusService
|
this.eventBus_ = eventBusService
|
||||||
|
|
||||||
@@ -86,4 +86,4 @@ class SearchSubscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SearchSubscriber
|
export default ProductSearchSubscriber
|
||||||
Reference in new issue
Block a user