@algolia/wizard 0.6.0-rc.55.29 → 0.6.0
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/dist/main.js +337 -1251
- package/docs/algolia-sdk/README.md +30 -53
- package/docs/algolia-sdk/search-single-index.md +42 -0
- package/package.json +1 -1
- package/docs/algolia-sdk/instantsearch-setup-templates.md +0 -92
- package/docs/algolia-sdk/save-records-csharp.md +0 -71
- package/docs/algolia-sdk/save-records-dart.md +0 -74
- package/docs/algolia-sdk/save-records-go.md +0 -62
- package/docs/algolia-sdk/save-records-java.md +0 -66
- package/docs/algolia-sdk/save-records-kotlin.md +0 -60
- package/docs/algolia-sdk/save-records-php.md +0 -50
- package/docs/algolia-sdk/save-records-python.md +0 -51
- package/docs/algolia-sdk/save-records-ruby.md +0 -48
- package/docs/algolia-sdk/save-records-scala.md +0 -68
- package/docs/algolia-sdk/save-records-swift.md +0 -88
|
@@ -1,59 +1,36 @@
|
|
|
1
|
-
# Algolia SDK reference
|
|
2
|
-
|
|
3
|
-
Authoritative reference for
|
|
4
|
-
documented here over prior knowledge — they are pinned to
|
|
5
|
-
and avoid known pitfalls (e.g. v5 type mismatches with
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| JavaScript/TypeScript | `algoliasearch` | `^5` |
|
|
19
|
-
| Python | `algoliasearch` | `>=4,<5` |
|
|
20
|
-
| Ruby | `algolia` | `~> 3.0` |
|
|
21
|
-
| PHP | `algolia/algoliasearch-client-php` | `^4` |
|
|
22
|
-
| Go | `github.com/algolia/algoliasearch-client-go/v4` | `v4` |
|
|
23
|
-
| Java | `com.algolia:algoliasearch` | `4.+` |
|
|
24
|
-
| Kotlin | `com.algolia:algoliasearch-client-kotlin` | `3.+` |
|
|
25
|
-
| Scala | `com.algolia:algoliasearch-scala_2.13` | `2.+` |
|
|
26
|
-
| C# | `Algolia.Search` | `7.*` |
|
|
27
|
-
| Swift | `algoliasearch-client-swift` | `9.0.0` |
|
|
28
|
-
| Dart | `algolia_client_search` | `^1.0.0` |
|
|
29
|
-
|
|
30
|
-
## Search UI
|
|
31
|
-
|
|
32
|
-
| Strategy | Doc | Packages |
|
|
33
|
-
| --- | --- | --- |
|
|
34
|
-
| React (incl. Next.js) | `instantsearch-setup-react.md` | `react-instantsearch` v7 |
|
|
35
|
-
| Vue (incl. Nuxt) | `instantsearch-setup-vue.md` | `vue-instantsearch` v4 |
|
|
36
|
-
| Angular | `instantsearch-setup-angular.md` | `instantsearch.js` v4 |
|
|
37
|
-
| Plain JavaScript | `instantsearch-setup-js.md` | `instantsearch.js` v4 |
|
|
38
|
-
| Server-rendered templates | `instantsearch-setup-templates.md` | CDN script tags, no bundler |
|
|
39
|
-
|
|
40
|
-
`angular-instantsearch` is DEPRECATED/archived (Sep 2024); use `instantsearch.js`.
|
|
41
|
-
|
|
42
|
-
Server-rendered templates cover Algolia's official framework integrations — Rails,
|
|
43
|
-
Django, Laravel, Symfony — and any backend with no JavaScript build.
|
|
1
|
+
# Algolia JS SDK reference (search)
|
|
2
|
+
|
|
3
|
+
Authoritative reference for wiring **Algolia search** in JavaScript/TypeScript apps.
|
|
4
|
+
Prefer the method shapes documented here over prior knowledge — they are pinned to
|
|
5
|
+
the current stable majors and avoid known pitfalls (e.g. v5 type mismatches with
|
|
6
|
+
InstantSearch).
|
|
7
|
+
|
|
8
|
+
## Versions
|
|
9
|
+
|
|
10
|
+
- `algoliasearch` v5 (install `^5`)
|
|
11
|
+
- `react-instantsearch` v7 (install `^7`)
|
|
12
|
+
- `vue-instantsearch` v4 (install `^4`)
|
|
13
|
+
- `instantsearch.js` v4 (install `^4`) — also the recommended choice for Angular
|
|
14
|
+
- `angular-instantsearch` — DEPRECATED/archived (Sep 2024); do not use, prefer `instantsearch.js`
|
|
15
|
+
|
|
16
|
+
Always install the **latest stable** within the major (use a caret range like `^5` /
|
|
17
|
+
`^7`); never pin an exact patch.
|
|
44
18
|
|
|
45
19
|
## Golden rules
|
|
46
20
|
|
|
47
|
-
- Ingestion is a **write** op: it needs a write key and must stay server-side. Read the
|
|
48
|
-
credentials from the `ALGOLIA_APPLICATION_ID` and `ALGOLIA_WRITE_API_KEY` env vars.
|
|
49
21
|
- Use a **search-only API key** in any browser/client code. It is safe to expose.
|
|
50
|
-
NEVER ship an admin or any write-capable key to the client
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
hardcode them inline.
|
|
22
|
+
NEVER ship an admin or any write-capable key to the client.
|
|
23
|
+
- Read the Application ID and search-only key from **public env vars**, never hardcode
|
|
24
|
+
them inline.
|
|
54
25
|
- Instantiate the search client **once, outside your components**, and pass a stable
|
|
55
|
-
reference. Do not inline `algoliasearch(...)` as a prop value — it breaks the
|
|
56
|
-
cache and causes re-renders.
|
|
26
|
+
reference. Do not inline `algoliasearch(...)` as a prop value — it breaks the
|
|
27
|
+
client cache and causes re-renders.
|
|
57
28
|
- For InstantSearch, import the client from `algoliasearch/lite` (smaller bundle and
|
|
58
|
-
correct types).
|
|
59
|
-
|
|
29
|
+
correct types — see `instantsearch-setup.md`).
|
|
30
|
+
|
|
31
|
+
## Files
|
|
32
|
+
|
|
33
|
+
- `instantsearch-setup.md` — framework-specific InstantSearch wiring (React, Vue,
|
|
34
|
+
Angular, vanilla). Use this for the in-app search UI.
|
|
35
|
+
- `search-single-index.md` — direct/manual search via the core client
|
|
36
|
+
(`searchSingleIndex`), for cases where InstantSearch is not used.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Direct search with the core client (v5)
|
|
2
|
+
|
|
3
|
+
Use this only when NOT using InstantSearch (e.g. a custom search box, a server
|
|
4
|
+
route, or programmatic queries). For UI, prefer `instantsearch-setup-<framework>.md`.
|
|
5
|
+
|
|
6
|
+
## Client
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { algoliasearch } from 'algoliasearch'
|
|
10
|
+
|
|
11
|
+
const client = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
In v5 there is no `client.initIndex(...)`. Index methods take the index name as a
|
|
15
|
+
parameter on the client. Every method takes a single options object.
|
|
16
|
+
|
|
17
|
+
## Search a single index
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
const { hits, nbHits } = await client.searchSingleIndex({
|
|
21
|
+
indexName: 'INDEX_NAME',
|
|
22
|
+
searchParams: { query: 'shoes', hitsPerPage: 20, page: 0 },
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Search multiple indices / queries in one request
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
const { results } = await client.search({
|
|
30
|
+
requests: [
|
|
31
|
+
{ indexName: 'INDEX_NAME', query: 'shoes' },
|
|
32
|
+
{ indexName: 'OTHER_INDEX', query: 'shoes' },
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- `searchSingleIndex` returns up to 1,000 hits. For larger exports use the `browse`
|
|
40
|
+
operation instead.
|
|
41
|
+
- Keep using a **search-only** key for any client-exposed search. Use an admin key
|
|
42
|
+
only in trusted server-side code.
|
package/package.json
CHANGED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# InstantSearch setup (CDN, server-rendered templates)
|
|
2
|
-
|
|
3
|
-
Use this when HTML is rendered server-side and there is no bundler or npm build
|
|
4
|
-
step: Rails ERB, Django templates, Laravel Blade, Symfony Twig.
|
|
5
|
-
|
|
6
|
-
## CDN tags (shared layout)
|
|
7
|
-
|
|
8
|
-
```html
|
|
9
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@8/themes/satellite-min.css">
|
|
10
|
-
<script src="https://cdn.jsdelivr.net/npm/algoliasearch@5/dist/lite/builds/browser.umd.js"></script>
|
|
11
|
-
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4/dist/instantsearch.production.min.js"></script>
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Globals these expose:
|
|
15
|
-
|
|
16
|
-
- `window['algoliasearch/lite']` → `{ liteClient }`. The lite UMD build's global is
|
|
17
|
-
the literal string key `algoliasearch/lite`, **not** `algoliasearch.liteClient`.
|
|
18
|
-
(`dist/algoliasearch.umd.js` is the full write-capable client under
|
|
19
|
-
`window.algoliasearch` — don't use it for search UI.)
|
|
20
|
-
- `window.instantsearch` → the callable factory, with `.widgets`, `.connectors`.
|
|
21
|
-
|
|
22
|
-
Floating `@5`/`@4`/`@8` track the newest patch. Adding SRI `integrity` requires
|
|
23
|
-
exact pins instead (Algolia's install page publishes hashes for
|
|
24
|
-
`algoliasearch@5.56.0`, `instantsearch.js@4.108.0`, `instantsearch.css@8.18.0`).
|
|
25
|
-
|
|
26
|
-
## Containers
|
|
27
|
-
|
|
28
|
-
```html
|
|
29
|
-
<div id="search"
|
|
30
|
-
data-algolia-app-id="APP_ID"
|
|
31
|
-
data-algolia-search-key="SEARCH_ONLY_KEY"
|
|
32
|
-
data-algolia-index="products">
|
|
33
|
-
<div id="searchbox"></div>
|
|
34
|
-
<div id="hits"></div>
|
|
35
|
-
</div>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Init
|
|
39
|
-
|
|
40
|
-
Inline `<script>` must run after both CDN scripts — put it at the end of `<body>`,
|
|
41
|
-
not in `<head>`.
|
|
42
|
-
|
|
43
|
-
```html
|
|
44
|
-
<script>
|
|
45
|
-
const el = document.getElementById('search')
|
|
46
|
-
const { liteClient: algoliasearch } = window['algoliasearch/lite']
|
|
47
|
-
const searchClient = algoliasearch(
|
|
48
|
-
el.dataset.algoliaAppId,
|
|
49
|
-
el.dataset.algoliaSearchKey
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
const search = instantsearch({ indexName: el.dataset.algoliaIndex, searchClient })
|
|
53
|
-
|
|
54
|
-
search.addWidgets([
|
|
55
|
-
instantsearch.widgets.searchBox({ container: '#searchbox' }),
|
|
56
|
-
instantsearch.widgets.hits({
|
|
57
|
-
container: '#hits',
|
|
58
|
-
templates: {
|
|
59
|
-
item(hit, { html, components }) {
|
|
60
|
-
return html`
|
|
61
|
-
<article>
|
|
62
|
-
<h3>${components.Highlight({ attribute: 'name', hit })}</h3>
|
|
63
|
-
<p>${hit.description}</p>
|
|
64
|
-
</article>
|
|
65
|
-
`
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
}),
|
|
69
|
-
])
|
|
70
|
-
|
|
71
|
-
search.start()
|
|
72
|
-
</script>
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`html` arrives as a property of the template function's second argument — it is
|
|
76
|
-
not an import and not a global. It escapes interpolated values, so it is the XSS
|
|
77
|
-
guard: never string-concatenate hit values or assign them to `innerHTML`.
|
|
78
|
-
|
|
79
|
-
## Injecting credentials from server config
|
|
80
|
-
|
|
81
|
-
Render App ID and the search-only key into `data-` attributes (every engine below
|
|
82
|
-
escapes attribute output), then read them from `dataset` — attribute dashes become
|
|
83
|
-
camelCase: `data-algolia-app-id` → `el.dataset.algoliaAppId`. Never interpolate a
|
|
84
|
-
credential into a JS string literal.
|
|
85
|
-
|
|
86
|
-
- ERB: `data-algolia-app-id="<%= Rails.application.credentials.algolia[:app_id] %>"`
|
|
87
|
-
- Django: `data-algolia-app-id="{{ algolia_app_id }}"` (from the view context)
|
|
88
|
-
- Blade: `data-algolia-app-id="{{ config('services.algolia.app_id') }}"`
|
|
89
|
-
- Twig: `data-algolia-app-id="{{ algolia_app_id }}"` (from a Twig global/parameter)
|
|
90
|
-
|
|
91
|
-
Only ever a **search-only** API key client-side. A write or admin key must never
|
|
92
|
-
appear in HTML, a `data-` attribute, or inline JS.
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Save records (Algolia.Search v7)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
The generated script is a self-contained console project at
|
|
6
|
-
`.algolia-wizard/ingest/ingest.csproj` + `Program.cs`, run with
|
|
7
|
-
`dotnet run --project .algolia-wizard/ingest/ingest.csproj`.
|
|
8
|
-
|
|
9
|
-
```xml
|
|
10
|
-
<Project Sdk="Microsoft.NET.Sdk">
|
|
11
|
-
<PropertyGroup>
|
|
12
|
-
<OutputType>Exe</OutputType>
|
|
13
|
-
<TargetFramework>net8.0</TargetFramework>
|
|
14
|
-
<ImplicitUsings>enable</ImplicitUsings>
|
|
15
|
-
<Nullable>enable</Nullable>
|
|
16
|
-
</PropertyGroup>
|
|
17
|
-
<ItemGroup>
|
|
18
|
-
<PackageReference Include="Algolia.Search" Version="7.*" />
|
|
19
|
-
</ItemGroup>
|
|
20
|
-
</Project>
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
`<OutputType>Exe</OutputType>` is required — `dotnet run` on a library has no entry
|
|
24
|
-
point. `<TargetFramework>` must match an installed SDK; `net8.0` (LTS) is the safe
|
|
25
|
-
default. Under Central Package Management (`Directory.Packages.props` at the repo
|
|
26
|
-
root) omit `Version` here and pin it there — `Version` on a `PackageReference` is
|
|
27
|
-
an error under CPM (NU1008).
|
|
28
|
-
|
|
29
|
-
```csharp
|
|
30
|
-
using System.Text.Json;
|
|
31
|
-
using Algolia.Search.Clients;
|
|
32
|
-
|
|
33
|
-
var appId = Environment.GetEnvironmentVariable("ALGOLIA_APPLICATION_ID")
|
|
34
|
-
?? throw new InvalidOperationException("ALGOLIA_APPLICATION_ID is not set");
|
|
35
|
-
var writeKey = Environment.GetEnvironmentVariable("ALGOLIA_WRITE_API_KEY")
|
|
36
|
-
?? throw new InvalidOperationException("ALGOLIA_WRITE_API_KEY is not set");
|
|
37
|
-
|
|
38
|
-
var client = new SearchClient(new SearchConfig(appId, writeKey));
|
|
39
|
-
var indexName = "products";
|
|
40
|
-
|
|
41
|
-
var records = new List<Dictionary<string, object>>
|
|
42
|
-
{
|
|
43
|
-
new() { ["objectID"] = "1", ["name"] = "Adam" },
|
|
44
|
-
new() { ["objectID"] = "2", ["name"] = "Benoit" },
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
var responses = await client.SaveObjectsAsync(indexName, records, waitForTasks: true);
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
```csharp
|
|
51
|
-
Task<List<BatchResponse>> SaveObjectsAsync<T>(
|
|
52
|
-
string indexName, IEnumerable<T> objects, bool waitForTasks = false,
|
|
53
|
-
int batchSize = 1000, RequestOptions options = null,
|
|
54
|
-
CancellationToken cancellationToken = default) where T : class;
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Records need an `objectID`; batching in 1,000s is automatic. Returns
|
|
58
|
-
`List<BatchResponse>` — one entry per batch, each `{ TaskID, ObjectIDs }`, never a
|
|
59
|
-
single response. `T` is constrained to `class`, so use `Dictionary<string, object>`
|
|
60
|
-
or a record/class, never a struct.
|
|
61
|
-
|
|
62
|
-
Read records from a JSON file:
|
|
63
|
-
|
|
64
|
-
```csharp
|
|
65
|
-
var json = await File.ReadAllTextAsync("records.json");
|
|
66
|
-
var records = JsonSerializer.Deserialize<List<Dictionary<string, object>>>(json)
|
|
67
|
-
?? new List<Dictionary<string, object>>();
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
71
|
-
stdout line; send all other logging to stderr so nothing follows it on stdout.
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Save records (algolia_client_search v1)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
Use the generated v2 client `algolia_client_search`, never the legacy community
|
|
6
|
-
`algolia` package. The script is run with `dart run .algolia-wizard/ingest.dart`.
|
|
7
|
-
|
|
8
|
-
```yaml
|
|
9
|
-
dependencies:
|
|
10
|
-
algolia_client_search: ^1.0.0
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
This client has **no `saveObjects` helper** (only `saveObjectsWithTransformation`,
|
|
14
|
-
which needs an Ingestion transformation) — use `batch` with `addObject` actions.
|
|
15
|
-
|
|
16
|
-
```dart
|
|
17
|
-
import 'dart:convert';
|
|
18
|
-
import 'dart:io';
|
|
19
|
-
import 'dart:math';
|
|
20
|
-
|
|
21
|
-
import 'package:algolia_client_search/algolia_client_search.dart';
|
|
22
|
-
|
|
23
|
-
Future<void> main() async {
|
|
24
|
-
final appId = Platform.environment['ALGOLIA_APPLICATION_ID'];
|
|
25
|
-
final writeKey = Platform.environment['ALGOLIA_WRITE_API_KEY'];
|
|
26
|
-
if (appId == null || writeKey == null) {
|
|
27
|
-
stderr.writeln('missing Algolia credentials');
|
|
28
|
-
exit(1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const indexName = 'products';
|
|
32
|
-
final client = SearchClient(appId: appId, apiKey: writeKey);
|
|
33
|
-
|
|
34
|
-
final records = <Map<String, dynamic>>[
|
|
35
|
-
{'objectID': '1', 'name': 'Adam'},
|
|
36
|
-
{'objectID': '2', 'name': 'Benoit'},
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
for (var i = 0; i < records.length; i += 1000) {
|
|
41
|
-
final chunk = records.sublist(i, min(i + 1000, records.length));
|
|
42
|
-
final response = await client.batch(
|
|
43
|
-
indexName: indexName,
|
|
44
|
-
batchWriteParams: BatchWriteParams(
|
|
45
|
-
requests: chunk
|
|
46
|
-
.map((r) => BatchRequest(action: Action.addObject, body: r))
|
|
47
|
-
.toList(),
|
|
48
|
-
),
|
|
49
|
-
);
|
|
50
|
-
stderr.writeln('task ${response.taskID}');
|
|
51
|
-
}
|
|
52
|
-
print('ALGOLIA_WIZARD_RECORD_COUNT=${records.length}');
|
|
53
|
-
} finally {
|
|
54
|
-
client.dispose();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
`batch` returns a **single** `BatchResponse { int taskID, List<String> objectIDs }`,
|
|
60
|
-
not a list. Gotchas: every record needs an `objectID`; there is no auto-chunking,
|
|
61
|
-
so cap each call at 1,000 records yourself; use the `Action.addObject` enum value
|
|
62
|
-
(`Action.updateObject` replaces instead of adds); and `client.dispose()` is
|
|
63
|
-
mandatory — without it `dart run` never exits.
|
|
64
|
-
|
|
65
|
-
Read records from a JSON file:
|
|
66
|
-
|
|
67
|
-
```dart
|
|
68
|
-
final json = await File('records.json').readAsString();
|
|
69
|
-
final records = (jsonDecode(json) as List).cast<Map<String, dynamic>>();
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
73
|
-
stdout line (before `dispose()` is fine); send all other logging to stderr so
|
|
74
|
-
nothing follows it on stdout.
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Save records (algoliasearch-client-go v4)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
Imports are the dependency declaration; `go mod tidy` resolves
|
|
6
|
-
`github.com/algolia/algoliasearch-client-go/v4`. Standalone `package main` file,
|
|
7
|
-
run with `go run`. Nothing panics on its own — every call returns `(value, error)`.
|
|
8
|
-
|
|
9
|
-
```go
|
|
10
|
-
package main
|
|
11
|
-
|
|
12
|
-
import (
|
|
13
|
-
"fmt"
|
|
14
|
-
"os"
|
|
15
|
-
|
|
16
|
-
"github.com/algolia/algoliasearch-client-go/v4/algolia/search"
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
func main() {
|
|
20
|
-
client, err := search.NewClient(os.Getenv("ALGOLIA_APPLICATION_ID"), os.Getenv("ALGOLIA_WRITE_API_KEY"))
|
|
21
|
-
if err != nil {
|
|
22
|
-
panic(err) // NewClient fails on an empty/invalid app ID or key
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
indexName := "products"
|
|
26
|
-
records := []map[string]any{{"objectID": "1", "name": "Hot 100"}}
|
|
27
|
-
|
|
28
|
-
if _, err := client.SaveObjects(indexName, records, search.WithWaitForTasks(true)); err != nil {
|
|
29
|
-
panic(err)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
fmt.Printf("ALGOLIA_WIZARD_RECORD_COUNT=%d\n", len(records))
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
```go
|
|
37
|
-
func (c *APIClient) SaveObjects(
|
|
38
|
-
indexName string,
|
|
39
|
-
objects []map[string]any, // maps only, each with an "objectID"
|
|
40
|
-
opts ...ChunkedBatchOption, // search.WithWaitForTasks(bool), search.WithBatchSize(int) (default 1000)
|
|
41
|
-
) ([]BatchResponse, error) // BatchResponse{ TaskID int64; ObjectIDs []string }
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
One `BatchResponse` per batch of 1,000, not per record — `len(res)` is the batch count.
|
|
45
|
-
|
|
46
|
-
Read records from a JSON file:
|
|
47
|
-
|
|
48
|
-
```go
|
|
49
|
-
import "encoding/json"
|
|
50
|
-
|
|
51
|
-
content, err := os.ReadFile("records.json")
|
|
52
|
-
if err != nil {
|
|
53
|
-
panic(err)
|
|
54
|
-
}
|
|
55
|
-
var records []map[string]any
|
|
56
|
-
if err := json.Unmarshal(content, &records); err != nil {
|
|
57
|
-
panic(err)
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
After a successful ingest print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` (n = records
|
|
62
|
-
read, not `len(res)`) as the last stdout line, trailing newline included.
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Save records (algoliasearch Java v4)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
```xml
|
|
6
|
-
<dependency>
|
|
7
|
-
<groupId>com.algolia</groupId>
|
|
8
|
-
<artifactId>algoliasearch</artifactId>
|
|
9
|
-
<version>4.20.0</version>
|
|
10
|
-
</dependency>
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
```groovy
|
|
14
|
-
implementation 'com.algolia:algoliasearch:4.20.0'
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
The class MUST be `AlgoliaWizardIngest` with a `public static void main`, in the
|
|
18
|
-
**default package** (no `package` statement) — the wizard runs a fixed main class.
|
|
19
|
-
|
|
20
|
-
```java
|
|
21
|
-
import com.algolia.api.SearchClient;
|
|
22
|
-
import java.util.List;
|
|
23
|
-
import java.util.Map;
|
|
24
|
-
|
|
25
|
-
public class AlgoliaWizardIngest {
|
|
26
|
-
|
|
27
|
-
public static void main(String[] args) throws Exception {
|
|
28
|
-
String indexName = "products";
|
|
29
|
-
List<Map<String, Object>> records = List.of(Map.of("objectID", "1", "name", "Hot 100"));
|
|
30
|
-
|
|
31
|
-
SearchClient client =
|
|
32
|
-
new SearchClient(System.getenv("ALGOLIA_APPLICATION_ID"), System.getenv("ALGOLIA_WRITE_API_KEY"));
|
|
33
|
-
try {
|
|
34
|
-
client.saveObjects(indexName, records);
|
|
35
|
-
System.out.printf("ALGOLIA_WIZARD_RECORD_COUNT=%d%n", records.size());
|
|
36
|
-
} finally {
|
|
37
|
-
client.close(); // required: okhttp's non-daemon threads keep the JVM alive otherwise
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Blocking API — calls return directly and throw `AlgoliaApiException` on failure.
|
|
44
|
-
|
|
45
|
-
```java
|
|
46
|
-
// objects: Maps or POJOs (Jackson-serialized), each with an objectID
|
|
47
|
-
<T> List<BatchResponse> saveObjects(String indexName, Iterable<T> objects)
|
|
48
|
-
<T> List<BatchResponse> saveObjects(String indexName, Iterable<T> objects,
|
|
49
|
-
boolean waitForTasks, int batchSize, RequestOptions requestOptions) // batchSize default 1000
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
One `BatchResponse` (`getTaskID()`, `getObjectIDs()`) per batch of 1,000, not per record.
|
|
53
|
-
|
|
54
|
-
Read records from a JSON file (Jackson is a transitive dependency):
|
|
55
|
-
|
|
56
|
-
```java
|
|
57
|
-
import com.fasterxml.jackson.core.type.TypeReference;
|
|
58
|
-
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
59
|
-
import java.io.File;
|
|
60
|
-
|
|
61
|
-
List<Map<String, Object>> records = new ObjectMapper()
|
|
62
|
-
.readValue(new File("records.json"), new TypeReference<List<Map<String, Object>>>() {});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
After a successful ingest print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` (n = records
|
|
66
|
-
read, not the returned list size) as the last stdout line.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Save records (algoliasearch-client-kotlin v3)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
Gradle Kotlin DSL. The client ships only `ktor-client-core`, so a JVM engine must
|
|
6
|
-
be declared too or the first call fails with no HTTP engine found:
|
|
7
|
-
|
|
8
|
-
```kotlin
|
|
9
|
-
implementation("com.algolia:algoliasearch-client-kotlin:3.23.0")
|
|
10
|
-
implementation("io.ktor:ktor-client-okhttp:3.2.0")
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
`saveObjects` is a `suspend` extension, so a standalone script wraps it in
|
|
14
|
-
`runBlocking`. The object MUST be `AlgoliaWizardIngest` in the **default package**
|
|
15
|
-
(no `package` statement), and `@JvmStatic` is required — a `fun main` inside an
|
|
16
|
-
object is not a JVM entrypoint without it.
|
|
17
|
-
|
|
18
|
-
```kotlin
|
|
19
|
-
import com.algolia.client.api.SearchClient
|
|
20
|
-
import com.algolia.client.extensions.*
|
|
21
|
-
import java.io.File
|
|
22
|
-
import kotlinx.coroutines.runBlocking
|
|
23
|
-
import kotlinx.serialization.json.*
|
|
24
|
-
|
|
25
|
-
object AlgoliaWizardIngest {
|
|
26
|
-
@JvmStatic
|
|
27
|
-
fun main(args: Array<String>): Unit = runBlocking {
|
|
28
|
-
val indexName = "products"
|
|
29
|
-
val records: List<JsonObject> = listOf(buildJsonObject { put("objectID", "1"); put("name", "Hot 100") })
|
|
30
|
-
|
|
31
|
-
// System.getenv returns String?; the constructor params are non-null
|
|
32
|
-
SearchClient(
|
|
33
|
-
appId = requireNotNull(System.getenv("ALGOLIA_APPLICATION_ID")),
|
|
34
|
-
apiKey = requireNotNull(System.getenv("ALGOLIA_WRITE_API_KEY")),
|
|
35
|
-
).use { client -> // AutoCloseable: without use/close, okhttp's non-daemon threads hang the JVM
|
|
36
|
-
client.saveObjects(indexName = indexName, objects = records)
|
|
37
|
-
println("ALGOLIA_WIZARD_RECORD_COUNT=${records.size}")
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
```kotlin
|
|
44
|
-
// objects is List<JsonObject> — not arbitrary data classes; each needs an objectID
|
|
45
|
-
suspend fun SearchClient.saveObjects(
|
|
46
|
-
indexName: String, objects: List<JsonObject>, waitForTasks: Boolean = false,
|
|
47
|
-
batchSize: Int = 1000, requestOptions: RequestOptions? = null,
|
|
48
|
-
): List<BatchResponse>
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
One `BatchResponse` (`taskID`, `objectIDs`) per batch of 1,000, not per record.
|
|
52
|
-
|
|
53
|
-
Read records from a JSON file (no serialization plugin needed for `JsonObject`):
|
|
54
|
-
|
|
55
|
-
```kotlin
|
|
56
|
-
val records = Json.parseToJsonElement(File("records.json").readText()).jsonArray.map { it.jsonObject }
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
After a successful ingest print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` (n = records
|
|
60
|
-
read, not the returned list size) as the last stdout line.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Save records (algoliasearch-client-php v4)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
Dependency: `algolia/algoliasearch-client-php` `^4` — the wizard runs
|
|
6
|
-
`composer require` for you; do not hand-edit `composer.json`.
|
|
7
|
-
|
|
8
|
-
`require 'vendor/autoload.php'` before anything else, or the class won't resolve
|
|
9
|
-
(from `.algolia-wizard/` the path is `__DIR__.'/../vendor/autoload.php'`).
|
|
10
|
-
|
|
11
|
-
```php
|
|
12
|
-
<?php
|
|
13
|
-
|
|
14
|
-
require __DIR__.'/../vendor/autoload.php';
|
|
15
|
-
|
|
16
|
-
use Algolia\AlgoliaSearch\Api\SearchClient;
|
|
17
|
-
|
|
18
|
-
$appId = getenv('ALGOLIA_APPLICATION_ID');
|
|
19
|
-
$apiKey = getenv('ALGOLIA_WRITE_API_KEY');
|
|
20
|
-
$indexName = 'playlists';
|
|
21
|
-
|
|
22
|
-
$client = SearchClient::create($appId, $apiKey);
|
|
23
|
-
$records = [['objectID' => '1', 'name' => 'Hot 100', 'visibility' => 'public']];
|
|
24
|
-
|
|
25
|
-
$responses = $client->saveObjects($indexName, $records, true);
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
```php
|
|
29
|
-
saveObjects(
|
|
30
|
-
string $indexName, // required
|
|
31
|
-
array $objects, // required
|
|
32
|
-
bool $waitForTasks = false,
|
|
33
|
-
int $batchSize = 1000,
|
|
34
|
-
array $requestOptions = []
|
|
35
|
-
) // => array of batch responses, one per 1,000-record batch
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Unlike the typed clients, PHP returns **plain associative arrays**, not objects:
|
|
39
|
-
`$responses[0]['taskID']`, `$responses[0]['objectIDs']`. Always an array of them —
|
|
40
|
-
never treat it as one response.
|
|
41
|
-
|
|
42
|
-
Read records from a JSON file:
|
|
43
|
-
|
|
44
|
-
```php
|
|
45
|
-
$records = json_decode(file_get_contents($recordsPath), true);
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
49
|
-
stdout line (`echo 'ALGOLIA_WIZARD_RECORD_COUNT='.count($records)."\n";`), with no
|
|
50
|
-
other output after it.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Save records (algoliasearch v4)
|
|
2
|
-
|
|
3
|
-
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
-
|
|
5
|
-
Dependency: `algoliasearch>=4,<5` (PyPI).
|
|
6
|
-
|
|
7
|
-
v4 is async-first: `SearchClient` is coroutine-based (every method needs `await`).
|
|
8
|
-
**`SearchClientSync` is the sync twin** — use it in a standalone script, via `with`
|
|
9
|
-
so the transport closes.
|
|
10
|
-
|
|
11
|
-
```python
|
|
12
|
-
import os
|
|
13
|
-
|
|
14
|
-
from algoliasearch.search.client import SearchClientSync
|
|
15
|
-
|
|
16
|
-
app_id = os.environ["ALGOLIA_APPLICATION_ID"]
|
|
17
|
-
api_key = os.environ["ALGOLIA_WRITE_API_KEY"]
|
|
18
|
-
index_name = "playlists"
|
|
19
|
-
records = [{"objectID": "1", "name": "Hot 100", "visibility": "public"}]
|
|
20
|
-
|
|
21
|
-
with SearchClientSync(app_id, api_key) as client:
|
|
22
|
-
responses = client.save_objects(
|
|
23
|
-
index_name=index_name,
|
|
24
|
-
objects=records,
|
|
25
|
-
wait_for_tasks=True,
|
|
26
|
-
)
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
```python
|
|
30
|
-
save_objects(
|
|
31
|
-
index_name: str, # required
|
|
32
|
-
objects: Iterable[Dict[str, Any]], # required
|
|
33
|
-
wait_for_tasks: bool = False,
|
|
34
|
-
batch_size: int = 1000,
|
|
35
|
-
) -> List[BatchResponse] # one entry per 1,000-record batch
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
`BatchResponse` attributes are **snake_case**: `r.task_id`, `r.object_ids` (the
|
|
39
|
-
wire keys are `taskID`/`objectIDs`). It is a list — never treat it as one object.
|
|
40
|
-
|
|
41
|
-
Read records from a JSON file:
|
|
42
|
-
|
|
43
|
-
```python
|
|
44
|
-
import json
|
|
45
|
-
|
|
46
|
-
with open(records_path, encoding="utf-8") as f:
|
|
47
|
-
records = json.load(f)
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
51
|
-
stdout line.
|