@vegan-friendly/strapi-plugin-elasticsearch 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
@@ -257,6 +257,111 @@ module.exports = (plugin) => {
|
|
257
257
|
- This will create a new route `/api/elasticsearch/enhanced-search` being served by the function defined above.
|
258
258
|
- You can add / modify the routes and controllers as necessary.
|
259
259
|
|
260
|
+
## Virtual Collections
|
261
|
+
|
262
|
+
**Virtual Collections** allow you to index and search data that does not directly map to a single Strapi collection type. This is useful for aggregating, transforming, or combining data from multiple sources before indexing it in Elasticsearch.
|
263
|
+
|
264
|
+
### What is a Virtual Collection?
|
265
|
+
|
266
|
+
A virtual collection is a logical grouping of data that you define, which can be indexed into Elasticsearch as if it were a regular Strapi collection. You control how the data is extracted, transformed, and indexed.
|
267
|
+
|
268
|
+
For example -
|
269
|
+
Let's say that you have two collections defined in Strapi:
|
270
|
+
|
271
|
+
- Restaurant
|
272
|
+
- Chain
|
273
|
+
|
274
|
+
* Each chain is related to one or more restaurants. Some restaurants don't have a chain.
|
275
|
+
|
276
|
+
Now let's say you want to index the restaurants, but in each restaurant you'd like to include some information about the restaurant, and you also want to merge some fields (e.g: if a Restaurant doesn't have a `description` - it inherits it from its chain ).
|
277
|
+
To do that, you need to create a virtual-collection in this plugin configuration, based on your existing restaurant collection.
|
278
|
+
|
279
|
+
### How to Register a Virtual Collection
|
280
|
+
|
281
|
+
To register a virtual collection, you need to provide a configuration object that implements the `VirtualCollectionConfig` interface. This is typically done in your plugin or project code.
|
282
|
+
|
283
|
+
**Example:**
|
284
|
+
|
285
|
+
```typescript
|
286
|
+
// src/extensions/elasticsearch/virtual-collections/my-virtual-collection.ts
|
287
|
+
|
288
|
+
import { VirtualCollectionConfig } from 'strapi-plugin-elasticsearch/server/types/virtual-collections.type';
|
289
|
+
|
290
|
+
const myVirtualCollection: VirtualCollectionConfig = {
|
291
|
+
collectionName: 'virtual::my-virtual-collection',
|
292
|
+
indexAlias: 'my_virtual_collection_index',
|
293
|
+
extractData: async (page, pageSize) => {
|
294
|
+
// Fetch and return an array of entities for the given page
|
295
|
+
// Example: aggregate data from multiple collections
|
296
|
+
return [];
|
297
|
+
},
|
298
|
+
extractByIds: async (ids) => {
|
299
|
+
// Fetch and return entities by their IDs
|
300
|
+
return [];
|
301
|
+
},
|
302
|
+
getIndexItemId: (itemId, collectionName) => `${collectionName}::${itemId}`,
|
303
|
+
triggers: [
|
304
|
+
{
|
305
|
+
collection: 'api::some-collection.some-collection',
|
306
|
+
getIdsToReindex: (event) => {
|
307
|
+
// Return an array of virtual collection item IDs to reindex
|
308
|
+
return [event.result.id];
|
309
|
+
},
|
310
|
+
},
|
311
|
+
],
|
312
|
+
mappings: {
|
313
|
+
// Optional: Elasticsearch mappings for this collection
|
314
|
+
},
|
315
|
+
};
|
316
|
+
|
317
|
+
export default myVirtualCollection;
|
318
|
+
```
|
319
|
+
|
320
|
+
### Key Properties
|
321
|
+
|
322
|
+
- **collectionName**: Unique name for your virtual collection.
|
323
|
+
- **indexAlias**: (Optional) Alias for the Elasticsearch index.
|
324
|
+
- **extractData(page, pageSize)**: Function to fetch paginated data for indexing.
|
325
|
+
- **extractByIds(ids)**: Function to fetch specific items by ID.
|
326
|
+
- **getIndexItemId(itemId, collectionName)**: (Optional) Function to generate unique Elasticsearch document IDs.
|
327
|
+
- **triggers**: Array of triggers that specify which Strapi collections should cause this virtual collection to reindex.
|
328
|
+
- **mappings**: (Optional) Elasticsearch mappings for the index.
|
329
|
+
|
330
|
+
### How Triggers Work
|
331
|
+
|
332
|
+
Each trigger listens to changes on a specified Strapi collection. When a change occurs, the `getIdsToReindex` function is called with the event data, and should return the IDs of the virtual collection items that need to be reindexed.
|
333
|
+
These items are then reindexed - they are fetched using `extractByIds` and are sent to ElasticSearch. If an item cannot be found using `extractByIds` - it is deleted from ElasticSearch.
|
334
|
+
|
335
|
+
### Registering the Virtual Collection
|
336
|
+
|
337
|
+
Register your virtual collection by specifying the `virtualCollections` property in this plugin's configuration, in `config/plugins.js`.
|
338
|
+
|
339
|
+
**Example:**
|
340
|
+
|
341
|
+
```javascript
|
342
|
+
// config/plugins.js
|
343
|
+
|
344
|
+
import myVirtualCollection from './virtual-collections/my-virtual-collection';
|
345
|
+
|
346
|
+
module.exports = async ({ env }) => {
|
347
|
+
return {
|
348
|
+
elasticsearch :{
|
349
|
+
enabled: true,
|
350
|
+
config: {
|
351
|
+
...
|
352
|
+
virtualCollections: [
|
353
|
+
myVirtualCollection,
|
354
|
+
]
|
355
|
+
}
|
356
|
+
}
|
357
|
+
}
|
358
|
+
};
|
359
|
+
```
|
360
|
+
|
361
|
+
### Indexing and Searching
|
362
|
+
|
363
|
+
Once registered, your virtual collection will be indexed according to the triggers and can be searched like any other indexed collection in Elasticsearch.
|
364
|
+
|
260
365
|
## Bugs
|
261
366
|
For any bugs, please create an issue [here](https://github.com/geeky-biz/strapi-plugin-elasticsearch/issues).
|
262
367
|
|
package/dist/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vegan-friendly/strapi-plugin-elasticsearch",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.3",
|
4
4
|
"description": "A Strapi plugin to enable using Elasticsearch with Strapi CMS.",
|
5
5
|
"homepage": "https://github.com/vegan-friendly/strapi-plugin-elasticsearch",
|
6
6
|
"strapi": {
|
package/dist/server/bootstrap.js
CHANGED
@@ -146,13 +146,13 @@ exports.default = async ({ strapi }) => {
|
|
146
146
|
strapi.db.lifecycles.subscribe({
|
147
147
|
models: [collectionUID],
|
148
148
|
afterCreate: async (event) => {
|
149
|
-
|
149
|
+
virtualCollectionIndexer.handleTriggerEvent(event);
|
150
150
|
},
|
151
151
|
afterUpdate: async (event) => {
|
152
|
-
|
152
|
+
virtualCollectionIndexer.handleTriggerEvent(event);
|
153
153
|
},
|
154
154
|
afterDelete: async (event) => {
|
155
|
-
|
155
|
+
virtualCollectionIndexer.handleTriggerEvent(event);
|
156
156
|
},
|
157
157
|
});
|
158
158
|
});
|
@@ -78,15 +78,20 @@ exports.default = ({ strapi }) => {
|
|
78
78
|
let prevPageData = [];
|
79
79
|
let totalIndexed = 0;
|
80
80
|
const pageLimit = 10000;
|
81
|
+
let pageErrorsInARow = 0;
|
81
82
|
while (page <= pageLimit) {
|
82
83
|
let pageData;
|
83
84
|
try {
|
84
85
|
pageData = await collection.extractData(page, pageSize);
|
86
|
+
pageErrorsInARow = 0;
|
85
87
|
}
|
86
88
|
catch (error) {
|
87
89
|
strapi.log.error(`Error extracting data for page ${page} of ${collectionName}: ${error.message}`);
|
88
90
|
errors += pageSize;
|
89
91
|
page++;
|
92
|
+
if (pageErrorsInARow++ > 5) {
|
93
|
+
throw new Error(`Too many errors while extracting data for ${collectionName} at page ${page}. Stopping reindexing.`);
|
94
|
+
}
|
90
95
|
continue;
|
91
96
|
}
|
92
97
|
strapi.log.debug(`Extracted ${pageData.length} items from ${collectionName} for page ${page}`);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vegan-friendly/strapi-plugin-elasticsearch",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.3",
|
4
4
|
"description": "A Strapi plugin to enable using Elasticsearch with Strapi CMS.",
|
5
5
|
"homepage": "https://github.com/vegan-friendly/strapi-plugin-elasticsearch",
|
6
6
|
"strapi": {
|