Repository: meilisearch/strapi-plugin-meilisearch (js)

Issue:
Mellisearch in strapi always requires to reload but does nothing.
**Description**

We have strapi installed with the official Meilisearch plugin provided by your team. After installing Meilisearch, we went to the dashboard and tried enabling the indexing for few collections. It says "Hooked" for some while most of them says "Reload required"

Since we were in production, reload was not an option. So, we started it in development mode and tried it again, yet it didn't work. This is how the dashboard looks:

![image](https://github.com/meilisearch/strapi-plugin-meilisearch/assets/128351505/b9e92785-a74d-4b36-8386-2469a59e81cb)

**Expected behavior**

Expected it to hook properly. But always wants a reload. Cannot reload in prod environment. Tried switching to dev mode, tried reloading, still the same, does not hook properly.

**Current behavior**

No matter what, indexer is not getting hooked.

**Screenshots or Logs**

- Meilisearch logs after enabling debug
```
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes::settings] returns: SummarizedTaskView { task_uid: 23, index_uid: Some("topic"), status: Enqueued, kind: SettingsUpdate, enqueued_at: 2023-05-19 4:58:34.246229097 +00:00:00 }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "PATCH /indexes/topic/settings HTTP/1.1" 202 123 "-" "undici" 0.004018
[2023-05-19T04:58:34Z INFO  index_scheduler] A batch of tasks was successfully completed.
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: PaginationView { results: [IndexView { uid: "author", created_at: 2023-05-18 7:11:02.117561552 +00:00:00, updated_at: 2023-05-18 7:11:02.154134628 +00:00:00, primary_key: None }, IndexView { uid: "esports-article", created_at: 2023-05-18 7:03:34.630672468 +00:00:00, updated_at: 2023-05-18 7:03:34.667910136 +00:00:00, primary_key: None }, IndexView { uid: "esports-category", created_at: 2023-05-18 7:11:09.531162555 +00:00:00, updated_at: 2023-05-18 7:11:09.566042633 +00:00:00, primary_key: None }, IndexView { uid: "esports-event", created_at: 2023-05-18 7:11:10.67140583 +00:00:00, updated_at: 2023-05-18 7:11:10.714302594 +00:00:00, primary_key: None }, IndexView { uid: "esports-match", created_at: 2023-05-18 7:11:12.662810604 +00:00:00, updated_at: 2023-05-18 7:11:12.698305125 +00:00:00, primary_key: None }, IndexView { uid: "esports-region", created_at: 2023-05-18 7:11:13.74167721 +00:00:00, updated_at: 2023-05-18 7:11:13.780603637 +00:00:00, primary_key: None }, IndexView { uid: "esports-team", created_at: 2023-05-18 7:11:14.310534463 +00:00:00, updated_at: 2023-05-18 7:11:14.346885675 +00:00:00, primary_key: None }, IndexView { uid: "esports-tournament-organizer", created_at: 2023-05-18 7:11:14.895599425 +00:00:00, updated_at: 2023-05-18 7:11:14.933894105 +00:00:00, primary_key: None }, IndexView { uid: "esports-update", created_at: 2023-05-18 7:11:15.738974626 +00:00:00, updated_at: 2023-05-18 7:11:15.776862909 +00:00:00, primary_key: None }, IndexView { uid: "game", created_at: 2023-05-18 7:11:17.874197378 +00:00:00, updated_at: 2023-05-18 7:11:17.909297608 +00:00:00, primary_key: None }, IndexView { uid: "gaming-article", created_at: 2023-05-18 7:11:17.364401846 +00:00:00, updated_at: 2023-05-18 7:11:17.399095424 +00:00:00, primary_key: None }, IndexView { uid: "gaming-category", created_at: 2023-05-18 7:11:23.06261196 +00:00:00, updated_at: 2023-05-18 7:11:23.095989567 +00:00:00, primary_key: None }, IndexView { uid: "gossip-article", created_at: 2023-05-18 7:11:24.123038769 +00:00:00, updated_at: 2023-05-18 7:11:24.15784716 +00:00:00, primary_key: None }, IndexView { uid: "gossip-category", created_at: 2023-05-18 7:11:26.656912622 +00:00:00, updated_at: 2023-05-18 7:11:26.691229735 +00:00:00, primary_key: None }, IndexView { uid: "label", created_at: 2023-05-18 7:11:28.857459036 +00:00:00, updated_at: 2023-05-18 7:11:28.892302295 +00:00:00, primary_key: None }, IndexView { uid: "platform", created_at: 2023-05-18 7:11:30.962409121 +00:00:00, updated_at: 2023-05-18 7:11:30.997759319 +00:00:00, primary_key: None }, IndexView { uid: "studio", created_at: 2023-05-18 7:11:31.566814032 +00:00:00, updated_at: 2023-05-18 7:11:31.600408069 +00:00:00, primary_key: None }, IndexView { uid: "tag", created_at: 2023-05-18 7:11:32.282865736 +00:00:00, updated_at: 2023-05-18 7:11:32.318280713 +00:00:00, primary_key: None }, IndexView { uid: "tech-article", created_at: 2023-05-18 7:11:33.120935494 +00:00:00, updated_at: 2023-05-18 7:11:33.155248888 +00:00:00, primary_key: None }, IndexView { uid: "tech-category", created_at: 2023-05-18 7:11:34.019636233 +00:00:00, updated_at: 2023-05-18 7:11:34.053531499 +00:00:00, primary_key: None }], offset: 0, limit: 20, total: 21 }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes HTTP/1.1" 200 2662 "-" "undici" 0.000616
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/author/stats HTTP/1.1" 200 65 "-" "undici" 0.000292
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/label/stats HTTP/1.1" 200 65 "-" "undici" 0.000329
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-article/stats HTTP/1.1" 200 65 "-" "undici" 0.000502
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-category/stats HTTP/1.1" 200 65 "-" "undici" 0.000575
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-event/stats HTTP/1.1" 200 65 "-" "undici" 0.000519
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-match/stats HTTP/1.1" 200 65 "-" "undici" 0.000389
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-team/stats HTTP/1.1" 200 65 "-" "undici" 0.000344
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-tournament-organizer/stats HTTP/1.1" 200 65 "-" "undici" 0.000418
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-update/stats HTTP/1.1" 200 65 "-" "undici" 0.000451
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/gaming-article/stats HTTP/1.1" 200 65 "-" "undici" 0.000296
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/gaming-category/stats HTTP/1.1" 200 65 "-" "undici" 0.000303
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/gossip-article/stats HTTP/1.1" 200 65 "-" "undici" 0.000251
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/gossip-category/stats HTTP/1.1" 200 65 "-" "undici" 0.000282
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/esports-region/stats HTTP/1.1" 200 65 "-" "undici" 0.000317
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/studio/stats HTTP/1.1" 200 65 "-" "undici" 0.000287
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/tag/stats HTTP/1.1" 200 65 "-" "undici" 0.000276
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/game/stats HTTP/1.1" 200 65 "-" "undici" 0.000251
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/tech-category/stats HTTP/1.1" 200 65 "-" "undici" 0.000254
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/tech-article/stats HTTP/1.1" 200 65 "-" "undici" 0.000246
[2023-05-19T04:58:34Z DEBUG meilisearch::routes::indexes] returns: IndexStats { number_of_documents: 0, is_indexing: false, field_distribution: {} }
[2023-05-19T04:58:34Z INFO  actix_web::middleware::logger] 172.24.0.5 "GET /indexes/platform/stats HTTP/1.1" 200 65 "-" "undici" 0.000284
```

- Strapi screenrecord on what's happening

https://cdn.discordapp.com/attachments/1108292293749907476/1108656367520202772/MeilisearchProblem.mp4

**Environment (please complete the following information):**
- OS: Linux
- Meilisearch version: v1.0.0
- strapi-plugin-meilisearch version: v0.9.2
- Browser: Firefox Version 113.0.1 (64-bit)
- Strapi version: v4.10.5


Pull request:
fix: getIndexes limited to 20 indexes
# Pull Request

## Related issue

Fixes #714

## Context
Selecting more than 20 collections in the Meilisearch plugin causes issues where collections can't be selected or are reset in the Meilisearch plugin.

## What does this PR do?
The issue is that when retrieving the indexes through the `getIndexes` function, there is a limit set automatically by Meilisearch to `20` ([See reference](https://www.meilisearch.com/docs/reference/api/indexes#list-all-indexes)). As a result, only 20 indexes will be returned and the later checks between indexes in Meilisearch and collections in Strapi are wrong.

This PR changes the call to Meilisearch from GET `/indexes` to GET `/stats` which does not have a `limit`.

- Update `getIndexes` to `getIndexUids` and use the `getStats` function from `meilisearch-js`
  - Return an array containing all the `indexUids`
- Update tests

## PR checklist
Please check if your PR fulfills the following requirements:
- [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
- [x] Have you read the contributing guidelines?
- [x] Have you made sure that the title is accurate and descriptive of the changes?

Thank you so much for contributing to Meilisearch!


Patch:
diff --git a/server/__mocks__/meilisearch.js b/server/__mocks__/meilisearch.js
index 6b0b004..e93b914 100644
--- a/server/__mocks__/meilisearch.js
+++ b/server/__mocks__/meilisearch.js
@@ -4,8 +4,23 @@ const updateSettingsMock = jest.fn(() => 10)
 const deleteDocuments = jest.fn(() => {
   return [{ taskUid: 1 }, { taskUid: 2 }]
 })
-const getIndexes = jest.fn(() => {
-  return { results: [{ uid: 'my_restaurant' }, { uid: 'restaurant' }] }
+const getStats = jest.fn(() => {
+  return {
+    databaseSize: 447819776,
+    lastUpdate: '2019-11-15T11:15:22.092896Z',
+    indexes: {
+      my_restaurant: {
+        numberOfDocuments: 1,
+        isIndexing: false,
+        fieldDistribution: {},
+      },
+      restaurant: {
+        numberOfDocuments: 1,
+        isIndexing: false,
+        fieldDistribution: {},
+      },
+    },
+  }
 })
 
 const getTasks = jest.fn(() => {
@@ -18,7 +33,7 @@ const getTasks = jest.fn(() => {
   }
 })
 
-const getStats = jest.fn(() => {
+const getIndexStats = jest.fn(() => {
   return { numberOfDocuments: 1, isIndexing: false, fieldDistribution: {} }
 })
 
@@ -27,13 +42,13 @@ const mockIndex = jest.fn(() => ({
   updateDocuments: updateDocumentsMock,
   updateSettings: updateSettingsMock,
   deleteDocuments,
-  getStats,
+  getStats: getIndexStats,
 }))
 
 // @ts-ignore
 const mock = jest.fn().mockImplementation(() => {
   return {
-    getIndexes,
+    getStats,
     index: mockIndex,
     getTasks,
   }
diff --git a/server/bootstrap.js b/server/bootstrap.js
index 7494821..9e10e65 100644
--- a/server/bootstrap.js
+++ b/server/bootstrap.js
@@ -31,8 +31,7 @@ async function syncIndexedCollections({
   contentTypeService,
   meilisearch,
 }) {
-  const indexes = await meilisearch.getIndexes()
-  const indexUids = indexes.map(index => index.uid)
+  const indexUids = await meilisearch.getIndexUids()
   // All indexed contentTypes
   const indexedContentTypes = await store.getIndexedContentTypes()
   const contentTypes = contentTypeService.getContentTypesUid()
diff --git a/server/services/meilisearch/connector.js b/server/services/meilisearch/connector.js
index a0918c5..23c18ca 100644
--- a/server/services/meilisearch/connector.js
+++ b/server/services/meilisearch/connector.js
@@ -65,16 +65,16 @@ module.exports = ({ strapi, adapter, config }) => {
 
   return {
     /**
-     * Get indexes with a safe guard in case of error.
+     * Get index uids with a safe guard in case of error.
      *
      * @returns { Promise<import("meilisearch").Index[]> }
      */
-    getIndexes: async function () {
+    getIndexUids: async function () {
       try {
         const { apiKey, host } = await store.getCredentials()
         const client = Meilisearch({ apiKey, host })
-        const { results: indexes } = await client.getIndexes()
-        return indexes
+        const { indexes } = await client.getStats()
+        return Object.keys(indexes)
       } catch (e) {
         strapi.log.error(`meilisearch: ${e.message}`)
         return []
@@ -176,8 +176,7 @@ module.exports = ({ strapi, adapter, config }) => {
      * }>}>} - List of contentTypes reports.
      */
     getContentTypesReport: async function () {
-      const indexes = await this.getIndexes()
-      const indexUids = indexes.map(index => index.uid)
+      const indexUids = await this.getIndexUids()
 
       // All listened contentTypes
       const listenedContentTypes = await store.getListenedContentTypes()


Test patch:
diff --git a/server/__tests__/meilisearch.test.js b/server/__tests__/meilisearch.test.js
index 3048c07..061fd9f 100644
--- a/server/__tests__/meilisearch.test.js
+++ b/server/__tests__/meilisearch.test.js
@@ -23,9 +23,9 @@ describe('Tests content types', () => {
       strapi: customStrapi,
     })
 
-    const indexes = await meilisearchService.getIndexes()
+    const indexes = await meilisearchService.getIndexUids()
 
-    expect(indexes).toEqual([{ uid: 'my_restaurant' }, { uid: 'restaurant' }])
+    expect(indexes).toEqual(['my_restaurant', 'restaurant'])
   })
 
   test('Test to delete entries from Meilisearch', async () => {