algoliasearch
Advanced tools
Comparing version 3.2.0 to 3.2.1
{ | ||
"name": "algoliasearch", | ||
"version": "3.2.0", | ||
"version": "3.2.1", | ||
"homepage": "https://github.com/algolia/algoliasearch-client-js", | ||
@@ -5,0 +5,0 @@ "authors": [ |
{ | ||
"name": "algoliasearch", | ||
"version": "3.2.0", | ||
"version": "3.2.1", | ||
"description": "AlgoliaSearch API JavaScript client", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
1045
README.md
# Algolia Search API Client for JavaScript | ||
**We recently (March 2015) released a new version (V3) of our JavaScript client, | ||
if you were using our previous version (V2), [read the migration guide](https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x)** | ||
**<New JavaScript clients>** | ||
In April 2015, we released a new JavaScript client (the one you are looking at) able to work in Node.js and the browser. | ||
If you were using our browser version (V2), [read the migration guide](https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x) | ||
If you were using our Node.js version (V1, npm `algolia-search`), [read the migration guide](https://github.com/algolia/algoliasearch-client-js/wiki/Node.js-v1.x.x-migration-guide) | ||
**</New JavaScript clients>** | ||
[Algolia Search](http://www.algolia.com) is a hosted full-text, numerical, and faceted search engine capable of delivering realtime results from the first keystroke. | ||
@@ -29,7 +37,8 @@ | ||
The JavaScript client lets you easily use the [Algolia Search API](https://www.algolia.com/doc/rest_api) in a browser. | ||
The JavaScript client lets you use the [Algolia Search API](https://www.algolia.com/doc/rest_api) on the frontend (browsers) or on the backend (Node.js) with the same API. | ||
It is dedicated to web apps searching directly from the browser. | ||
To add, remove or delete your objects please consider using [a backend API client](https://www.algolia.com/doc). | ||
We support callbacks and promises. | ||
**Most of the time you should do your indexing on the backend with Node.js and your search experience in the browser by speaking directly with Algolia servers. So that your admin keys will not leak on the internet and your users get the best performance** | ||
Our JavaScript library is [UMD](https://github.com/umdjs/umd) compatible, you can | ||
@@ -40,6 +49,4 @@ use it with any module loader. | ||
If you are using the V2 of our JavaScript client and want to upgrade, please read [our migration guide](https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x). | ||
Table of Contents | ||
@@ -50,3 +57,11 @@ ================= | ||
1. [Setup](#setup) | ||
- [Frontend](#frontend) | ||
- [Node.js](#nodejs) | ||
- [Parse.com](#parsecom-) | ||
1. [Quick Start](#quick-start) | ||
- [Frontend](#frontend-1) | ||
- [Vanilla JavaScript](#vanilla-javascript) | ||
- [jQuery module](#jquery-module) | ||
- [AngularJS module](#angularjs-module) | ||
- [Backend (Node.js)](#backend-nodejs) | ||
1. [Callback convention](#callback-convention) | ||
@@ -56,2 +71,4 @@ 1. [Promises](#promises) | ||
1. [Cache](#cache) | ||
1. [Proxy support](#proxy-support) | ||
1. [Keep-alive](#keep-alive) | ||
1. [Online documentation](#documentation) | ||
@@ -62,7 +79,19 @@ 1. [Tutorials](#tutorials) | ||
1. [Add a new object](#add-a-new-object-to-the-index) | ||
1. [Update an object](#update-an-existing-object-in-the-index) | ||
1. [Search](#search) | ||
1. [Multiple queries](#multiple-queries) | ||
1. [Get an object](#get-an-object) | ||
1. [Security](#security) | ||
1. [Delete an object](#delete-an-object) | ||
1. [Delete by query](#delete-by-query) | ||
1. [Index settings](#index-settings) | ||
1. [List indices](#list-indices) | ||
1. [Delete an index](#delete-an-index) | ||
1. [Clear an index](#clear-an-index) | ||
1. [Wait indexing](#wait-indexing) | ||
1. [Batch writes](#batch-writes) | ||
1. [Security / User API Keys](#security--user-api-keys) | ||
1. [Copy or rename an index](#copy-or-rename-an-index) | ||
1. [Backup / Retrieve all index content](#backup--retrieve-of-all-index-content) | ||
1. [Logs](#logs) | ||
@@ -79,2 +108,6 @@ | ||
### Frontend | ||
You can either use a package manager like npm or include a `<script>` tag. | ||
#### npm | ||
@@ -94,7 +127,7 @@ | ||
#### jsDelivr | ||
#### <script> tag using jsDelivr | ||
[jsDelivr](http://www.jsdelivr.com/about.php) is a global CDN delivery for JavaScript libraries. | ||
You can always get the latest, backward compatible version by including: | ||
To include the latest releases and all upcoming features and patches, use this: | ||
@@ -105,8 +138,71 @@ ```html | ||
### Example | ||
#### Browserify, webpack | ||
```sh | ||
npm install algoliasearch --save | ||
``` | ||
```js | ||
var algoliasearch = require('algoliasearch'); | ||
var client = algoliasearch('applicationID', 'apiKey'); | ||
var index = client.initIndex('indexName'); | ||
index.search('something', function searchDone(err, content) { | ||
console.log(err, content); | ||
}); | ||
``` | ||
### Node.js | ||
```sh | ||
npm install algoliasearch --save | ||
``` | ||
```js | ||
var algoliasearch = require('algoliasearch'); | ||
var client = algoliasearch('applicationID', 'apiKey'); | ||
var index = client.initIndex('indexName'); | ||
index.search('something', function searchDone(err, content) { | ||
console.log(err, content); | ||
}); | ||
``` | ||
### Parse.com | ||
```sh | ||
curl https://raw.githubusercontent.com/algolia/algoliasearch-client-js/master/dist/algoliasearch.parse.js -o /your/parse/project/cloud/algoliasearch.parse.js | ||
``` | ||
In `cloud/main.js` for example: | ||
```js | ||
var algoliasearch = require('cloud/algoliasearch.parse.js'); | ||
var client = algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76'); | ||
var index = client.initIndex('contacts'); | ||
Parse.Cloud.define("hello", function(request, response) { | ||
index.search('Atlenta', function(err, results) { | ||
if (err) { | ||
throw err; | ||
} | ||
response.success('We got ' + results.nbHits + ' results'); | ||
}); | ||
}); | ||
``` | ||
Quick Start | ||
------------- | ||
### Frontend | ||
To build your frontend search experience, also check out our [examples](./examples/) and [tutorials](https://www.algolia.com/doc/tutorials). | ||
#### Vanilla JavaScript | ||
```html | ||
<script src="//cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js"></script> | ||
<script> | ||
var client = algoliasearch('ApplicationID', 'Search-Only-API-Key'); | ||
var client = algoliasearch('ApplicationID', 'apiKey'); | ||
var index = client.initIndex('indexName'); | ||
@@ -128,6 +224,3 @@ | ||
Have a look at our [callback convention](#callback-convention), read about [our promises](#promises). | ||
#### jQuery | ||
#### jQuery module | ||
We provide a specific [jQuery](http://jquery.com/) build that will use [jQuery.ajax](http://api.jquery.com/jquery.ajax/). | ||
@@ -141,3 +234,3 @@ | ||
<script> | ||
var client = $.algolia.Client('ApplicationID', 'Search-Only-API-Key'); | ||
var client = $.algolia.Client('ApplicationID', 'apiKey'); | ||
var index = client.initIndex('indexName'); | ||
@@ -150,4 +243,3 @@ index.search('something', function searchDone(err, content) { | ||
#### Angular.js | ||
#### AngularJS module | ||
We provide a specific [AngularJS](https://angularjs.org/) build that is using the [$http service](https://docs.angularjs.org/api/ng/service/$http). | ||
@@ -166,3 +258,3 @@ | ||
$scope.hits = []; | ||
var client = algolia.Client('ApplicationID', 'Search-Only-API-Key'); | ||
var client = algolia.Client('ApplicationID', 'apiKey'); | ||
var index = client.initIndex('indexName'); | ||
@@ -179,50 +271,76 @@ index.search('something') | ||
#### Browserify | ||
### Backend (Node.js) | ||
```sh | ||
npm install algoliasearch --save | ||
``` | ||
In 30 seconds, this quick start tutorial will show you how to index and search objects. | ||
Without any prior configuration, you can start indexing [500 contacts](https://github.com/algolia/algoliasearch-client-csharp/blob/master/contacts.json) in the `contacts` index using the following code: | ||
```js | ||
var algoliasearch = require('algoliasearch'); | ||
var client = algoliasearch('applicationID', 'Search-Only-API-Key'); | ||
var index = client.initIndex('indexName'); | ||
index.search('something', function searchDone(err, content) { | ||
console.log(err, content); | ||
var index = client.initIndex('contacts'); | ||
var contactsJSON = require('./contacts.json'); | ||
index.addObjects(contactsJSON, function(err, content) { | ||
if (err) { | ||
console.error(err); | ||
} | ||
}); | ||
``` | ||
We also provide [runnable examples](#quick-start) for you to try. | ||
You can now search for contacts using firstname, lastname, company, etc. (even with typos): | ||
```js | ||
// firstname | ||
index.search('jimmie', function(err, content) { | ||
console.log(content.hits); | ||
}); | ||
// firstname with typo | ||
index.search('jimie', function(err, content) { | ||
console.log(content.hits); | ||
}); | ||
// a company | ||
index.search('california paint', function(err, content) { | ||
console.log(content.hits); | ||
}); | ||
// a firstname & company | ||
index.search('jimmie paint', function(err, content) { | ||
console.log(content.hits); | ||
}); | ||
``` | ||
Settings can be customized to tune the search behavior. For example, you can add a custom sort by number of followers to the already great built-in relevance: | ||
```js | ||
index.setSettings({ | ||
'customRanking': ['desc(followers)'] | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Quick Start | ||
------------- | ||
We have easy to run [examples](./examples/) for you to try. First, setup the repository: | ||
```sh | ||
git clone https://github.com/algolia/algoliasearch-client-js.git | ||
cd algoliasearch-client-js | ||
npm install | ||
npm run examples | ||
You can also configure the list of attributes you want to index by order of importance (first = most important): | ||
```js | ||
index.setSettings({ | ||
'attributesToIndex': [ | ||
'lastname', | ||
'firstname', | ||
'company', | ||
'email', | ||
'city', | ||
'address' | ||
] | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Then open either: | ||
- http://127.0.0.1:8080/examples/ to see a list of examples | ||
- http://127.0.0.1:8080/examples/autocomplete.html | ||
- http://127.0.0.1:8080/examples/instantsearch.html | ||
Since the engine is designed to suggest results as you type, you'll generally search by prefix. In this case the order of attributes is very important to decide which hit is the best: | ||
```js | ||
index.search('or', function(err, content) { | ||
console.log(content.hits); | ||
}); | ||
To hack and use your own indexes and data, open one of the example file and replace: | ||
```js | ||
var client = algoliasearch('ApplicationID', 'Search-Only-API-Key'); | ||
var index = client.initIndex(indexName); | ||
index.search('jim', function(err, content) { | ||
console.log(content.hits); | ||
}); | ||
``` | ||
@@ -233,17 +351,14 @@ | ||
Callback convention | ||
------------- | ||
All API calls will return the result in a callback that takes two arguments: | ||
Every API call takes a callback as last parameter. This callback will then be called with two arguments: | ||
1. **error**: null or an [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object. More info on the error can be find in `error.message`. | ||
2. **content**: the object containing the answer | ||
2. **content**: the object containing the answer from the server, it's a JavaScript object | ||
We follow the [error-first callback](http://thenodeway.io/posts/understanding-error-first-callbacks/). | ||
Promises | ||
------------- | ||
If **you do not provide a callback**, you will get a promise (but never both). | ||
**If you do not provide a callback**, you will get a promise (but never both). | ||
@@ -258,12 +373,23 @@ Promises are the [native Promise implementation](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise). | ||
The request strategy used by the JavaScript client includes: | ||
- [CORS](http://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing#Browser_support) for modern browsers | ||
- [XDomainRequest](https://msdn.microsoft.com/en-us/library/ie/cc288060%28v=vs.85%29.aspx) for IE <= 10 | ||
- [JSONP](http://en.wikipedia.org/wiki/JSONP) in any situation where Ajax requests are unavailabe or blocked. | ||
- On the browser: | ||
+ [CORS](http://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing#Browser_support) for modern browsers | ||
+ [XDomainRequest](https://msdn.microsoft.com/en-us/library/ie/cc288060%28v=vs.85%29.aspx) for IE <= 10 | ||
+ [JSONP](http://en.wikipedia.org/wiki/JSONP) in any situation where Ajax requests are unavailabe or blocked. | ||
- Node.js: | ||
+ native [`http` module](https://nodejs.org/api/) | ||
Connections are always `keep-alive`. | ||
Cache | ||
------------- | ||
Queries will be stored in a ```cache``` inside your JavaScript ```Index``` and ```AlgoliaSearch``` objects to avoid performing the same API calls twice. It's particularly useful when your users are deleting characters or words from the current query but has a chance of ending up with outdated results if the page isn't refreshed for some time. | ||
**Browser only** | ||
To address this issue, be sure to clear the cache every X minutes to ensure you have up to date results: | ||
To avoid performing the same API calls twice **search** results will be stored in a `cache` that will be tied to your JavaScript `client` and `index` objects. | ||
It's particularly useful when your users are deleting characters or words from the current query but has a chance of ending up with outdated results if the page isn't refreshed for some time. | ||
If at any point you want to clear the cache, just do this: | ||
```js | ||
@@ -278,19 +404,44 @@ // clear the queries cache | ||
Proxy support | ||
------------ | ||
**Node.js only** | ||
If you are behind a proxy, just set `HTTP_PROXY` or `HTTPS_PROXY` environment variables before starting your Node.js program. | ||
```sh | ||
HTTP_PROXY=http://someproxy.com:9320 node main.js | ||
``` | ||
Keep-alive | ||
------------- | ||
**Node.js only** | ||
Keep-alive is activated by default. | ||
Because of the nature of keepalive connections, your process will hang even if you do not do any more command using the `client`. | ||
To fix this, we expose a `client.destroy()` method that will terminate all remaining alive connections. | ||
You should call this method when you are finished working with the AlgoliaSearch API. So that your process will exit gently. | ||
**Note: keep-alive is still always activated in browsers, this is a native behavior of browsers.** | ||
Documentation | ||
================ | ||
Check our [online documentation](http://www.algolia.com/doc/): | ||
* [Initial Import](http://www.algolia.com/doc/#InitialImport) | ||
* [Ranking & Relevance](http://www.algolia.com/doc/#RankingRelevance) | ||
* [Indexing](http://www.algolia.com/doc/#Indexing) | ||
* [Search](http://www.algolia.com/doc/#Search) | ||
* [Sorting](http://www.algolia.com/doc/#Sorting) | ||
* [Filtering](http://www.algolia.com/doc/#Filtering) | ||
* [Faceting](http://www.algolia.com/doc/#Faceting) | ||
* [Geo-Search](http://www.algolia.com/doc/#Geo-Search) | ||
* [Security](http://www.algolia.com/doc/#Security) | ||
Check our [online documentation](http://www.algolia.com/doc/guides/node): | ||
* [Initial Import](http://www.algolia.com/doc/guides/node#InitialImport) | ||
* [Ranking & Relevance](http://www.algolia.com/doc/guides/node#RankingRelevance) | ||
* [Indexing](http://www.algolia.com/doc/guides/node#Indexing) | ||
* [Search](http://www.algolia.com/doc/guides/node#Search) | ||
* [Sorting](http://www.algolia.com/doc/guides/node#Sorting) | ||
* [Filtering](http://www.algolia.com/doc/guides/node#Filtering) | ||
* [Faceting](http://www.algolia.com/doc/guides/node#Faceting) | ||
* [Geo-Search](http://www.algolia.com/doc/guides/node#Geo-Search) | ||
* [Security](http://www.algolia.com/doc/guides/node#Security) | ||
* [REST API](http://www.algolia.com/doc/rest) | ||
Tutorials | ||
@@ -311,2 +462,147 @@ ================ | ||
Add a new object to the Index | ||
------------- | ||
Each entry in an index has a unique identifier called `objectID`. There are two ways to add en entry to the index: | ||
1. Using automatic `objectID` assignment. You will be able to access it in the answer. | ||
2. Supplying your own `objectID`. | ||
You don't need to explicitly create an index, it will be automatically created the first time you add an object. | ||
Objects are schema less so you don't need any configuration to start indexing. If you wish to configure things, the settings section provides details about advanced settings. | ||
Example with automatic `objectID` assignment: | ||
```js | ||
index.addObject({ | ||
firstname: 'Jimmie', | ||
lastname: 'Barninger' | ||
}, function(err, content) { | ||
console.log('objectID=' + content.objectID); | ||
}); | ||
``` | ||
Example with manual `objectID` assignment: | ||
```js | ||
index.addObject({ | ||
firstname: 'Jimmie', | ||
lastname: 'Barninger' | ||
}, 'myID', function(err, content) { | ||
console.log('objectID=' + content.objectID); | ||
}); | ||
``` | ||
Update an existing object in the Index | ||
------------- | ||
You have three options when updating an existing object: | ||
1. Replace all its attributes. | ||
2. Replace only some attributes. | ||
3. Apply an operation to some attributes. | ||
Example on how to replace all attributes of an existing object: | ||
```js | ||
index.saveObject({ | ||
firstname: 'Jimmie', | ||
lastname: 'Barninger', | ||
city: 'New York', | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
You have many ways to update an object's attributes: | ||
1. Set the attribute value | ||
2. Add an element to an array | ||
3. Remove an element from an array | ||
4. Add an element to an array if it doesn't exist | ||
5. Increment an attribute | ||
6. Decrement an attribute | ||
Example to update only the city attribute of an existing object: | ||
```js | ||
index.partialUpdateObject({ | ||
city: 'San Francisco', | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example to add a tag: | ||
```js | ||
index.partialUpdateObject({ | ||
_tags: { | ||
value: 'MyTag', | ||
_operation: 'Add' | ||
}, | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example to remove a tag: | ||
```js | ||
index.partialUpdateObject({ | ||
_tags: { | ||
value: 'MyTag', | ||
_operation:'Remove' | ||
}, | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example to add a tag if it doesn't exist: | ||
```js | ||
index.partialUpdateObject({ | ||
_tags: { | ||
value: 'MyTag', | ||
_operation: 'AddUnique' | ||
}, | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example to increment a numeric value: | ||
```js | ||
index.partialUpdateObject({ | ||
price: { | ||
value: 42, | ||
_operation: 'Increment' | ||
}, | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example to decrement a numeric value: | ||
```js | ||
index.partialUpdateObject({ | ||
price: { | ||
value: 42, | ||
_operation: 'Decrement' | ||
}, | ||
objectID: 'myID' | ||
}, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Search | ||
@@ -416,18 +712,15 @@ ------------- | ||
// with params | ||
index.search( | ||
'query string', { | ||
attributesToRetrieve: ['firstname', 'lastname'], | ||
hitsPerPage: 50 | ||
}, | ||
function searchDone(err, content) { | ||
if (err) { | ||
console.error(err); | ||
return; | ||
} | ||
index.search('query string', { | ||
attributesToRetrieve: ['firstname', 'lastname'], | ||
hitsPerPage: 50 | ||
}, function searchDone(err, content) { | ||
if (err) { | ||
console.error(err); | ||
return; | ||
} | ||
for (var h in content.hits) { | ||
console.log('Hit(' + content.hits[h].objectID + '): ' + content.hits[h].toString()); | ||
} | ||
for (var h in content.hits) { | ||
console.log('Hit(' + content.hits[h].objectID + '): ' + content.hits[h].toString()); | ||
} | ||
); | ||
}); | ||
``` | ||
@@ -476,35 +769,24 @@ | ||
```javascript | ||
var client = algoliasearch('ApplicationID', 'Search-Only-API-Key'); | ||
```js | ||
var client = algoliasearch('ApplicationID', 'apiKey'); | ||
// perform 3 queries in a single API call: | ||
// - 1st query targets index `categories` | ||
// - 2nd and 3rd queries target index `products` | ||
client.startQueriesBatch(); | ||
client.addQueryInBatch( | ||
'categories', // index name | ||
'search in categories index', { | ||
var queries = [{ | ||
indexName: 'categories', | ||
query: 'search in categories index', { | ||
hitsPerPage: 3 | ||
} | ||
); | ||
client.addQueryInBatch( | ||
'products', | ||
'first search in products', { | ||
}, { | ||
indexName: 'products', | ||
query: 'first search in products', { | ||
hitsPerPage: 3, | ||
tagFilters: 'promotion' | ||
} | ||
); | ||
client.addQueryInBatch( | ||
'products', | ||
'another search in products', { | ||
}, { | ||
indexName: 'products', | ||
query: 'another search in products', { | ||
hitsPerPage: 10 | ||
} | ||
); | ||
}]; | ||
client.sendQueriesBatch(searchMultiCallback); | ||
function searchMultiCallback(err, content) { | ||
function searchCallback(err, content) { | ||
if (err) { | ||
@@ -530,2 +812,7 @@ console.error(err); | ||
} | ||
// perform 3 queries in a single API call: | ||
// - 1st query targets index `categories` | ||
// - 2nd and 3rd queries target index `products` | ||
client.search(queries, searchCallback); | ||
``` | ||
@@ -540,18 +827,406 @@ | ||
```javascript | ||
var client = algoliasearch('ApplicationID', 'Search-Only-API-Key'); | ||
var index = client.initIndex('indexName'); | ||
```js | ||
// Retrieves all attributes | ||
index.getObject('myID', function(err, content) { | ||
console.log(content.objectID + ": " + content.toString()); | ||
}); | ||
// Retrieves all attributes | ||
index.getObject('myID', function searchDone(err, content) { | ||
if (err) { | ||
console.error(err); | ||
return; | ||
// Retrieves firstname and lastname attributes | ||
index.getObject('myID', ['firstname', 'lastname'], function(err, content) { | ||
console.log(content.objectID + ": " + content.toString()); | ||
}); | ||
``` | ||
You can also retrieve a set of objects: | ||
```js | ||
index.getObjects(['myObj1', 'myObj2'], function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Delete an object | ||
------------- | ||
You can delete an object using its `objectID`: | ||
```js | ||
index.deleteObject('myID', function(error) { | ||
if (!err) { | ||
console.log('success'); | ||
} | ||
}); | ||
``` | ||
console.log(content.objectID + ": ", content); | ||
Delete by query | ||
------------- | ||
You can delete all objects matching a single query with the following code. Internally, the API client performs the query, deletes all matching hits, and waits until the deletions have been applied. | ||
```js | ||
// no query parameters | ||
index.deleteByQuery('John', function(error) { | ||
if (!err) { | ||
console.log('success'); | ||
} | ||
}); | ||
// Retrieves firstname and lastname attributes | ||
index.getObject('myID', ['firstname', 'lastname'], function searchDone(err, content) { | ||
// with query parameters | ||
index.deleteByQuery('John', { | ||
some: 'query', | ||
param: 'eters' | ||
}, function(error) { | ||
if (!err) { | ||
console.log('success'); | ||
} | ||
}); | ||
``` | ||
Index Settings | ||
------------- | ||
You can retrieve all settings using the `getSettings` function. The result will contain the following attributes: | ||
#### Indexing parameters | ||
* **attributesToIndex**: (array of strings) The list of fields you want to index.<br/>If set to null, all textual and numerical attributes of your objects are indexed. Be sure to update it to get optimal results.<br/>This parameter has two important uses: | ||
* *Limit the attributes to index*.<br/>For example, if you store a binary image in base64, you want to store it and be able to retrieve it, but you don't want to search in the base64 string. | ||
* *Control part of the ranking*.<br/>(see the ranking parameter for full explanation) Matches in attributes at the beginning of the list will be considered more important than matches in attributes further down the list. In one attribute, matching text at the beginning of the attribute will be considered more important than text after. You can disable this behavior if you add your attribute inside `unordered(AttributeName)`. For example, `attributesToIndex: ["title", "unordered(text)"]`. | ||
**Notes**: All numerical attributes are automatically indexed as numerical filters. If you don't need filtering on some of your numerical attributes, please consider sending them as strings to speed up the indexing.<br/> | ||
You can decide to have the same priority for two attributes by passing them in the same string using a comma as a separator. For example `title` and `alternative_title` have the same priority in this example, which is different than text priority: `attributesToIndex:["title,alternative_title", "text"]`. | ||
* **attributesForFaceting**: (array of strings) The list of fields you want to use for faceting. All strings in the attribute selected for faceting are extracted and added as a facet. If set to null, no attribute is used for faceting. | ||
* **attributeForDistinct**: The attribute name used for the `Distinct` feature. This feature is similar to the SQL "distinct" keyword. When enabled in queries with the `distinct=1` parameter, all hits containing a duplicate value for this attribute are removed from results. For example, if the chosen attribute is `show_name` and several hits have the same value for `show_name`, then only the best one is kept and others are removed. **Note**: This feature is disabled if the query string is empty and there aren't any `tagFilters`, `facetFilters`, nor `numericFilters` parameters. | ||
* **ranking**: (array of strings) Controls the way results are sorted.<br/>We have nine available criteria: | ||
* **typo**: Sort according to number of typos. | ||
* **geo**: Sort according to decreasing distance when performing a geo location based search. | ||
* **words**: Sort according to the number of query words matched by decreasing order. This parameter is useful when you use the `optionalWords` query parameter to have results with the most matched words first. | ||
* **proximity**: Sort according to the proximity of the query words in hits. | ||
* **attribute**: Sort according to the order of attributes defined by attributesToIndex. | ||
* **exact**: | ||
* If the user query contains one word: sort objects having an attribute that is exactly the query word before others. For example, if you search for the TV show "V", you want to find it with the "V" query and avoid getting all popular TV shows starting by the letter V before it. | ||
* If the user query contains multiple words: sort according to the number of words that matched exactly (not as a prefix). | ||
* **custom**: Sort according to a user defined formula set in the **customRanking** attribute. | ||
* **asc(attributeName)**: Sort according to a numeric attribute using ascending order. **attributeName** can be the name of any numeric attribute in your records (integer, double or boolean). | ||
* **desc(attributeName)**: Sort according to a numeric attribute using descending order. **attributeName** can be the name of any numeric attribute in your records (integer, double or boolean). <br/>The standard order is ["typo", "geo", "words", "proximity", "attribute", "exact", "custom"]. | ||
* **customRanking**: (array of strings) Lets you specify part of the ranking.<br/>The syntax of this condition is an array of strings containing attributes prefixed by the asc (ascending order) or desc (descending order) operator. For example, `"customRanking" => ["desc(population)", "asc(name)"]`. | ||
* **queryType**: Select how the query words are interpreted. It can be one of the following values: | ||
* **prefixAll**: All query words are interpreted as prefixes. | ||
* **prefixLast**: Only the last word is interpreted as a prefix (default behavior). | ||
* **prefixNone**: No query word is interpreted as a prefix. This option is not recommended. | ||
* **separatorsToIndex**: Specify the separators (punctuation characters) to index. By default, separators are not indexed. Use `+#` to be able to search Google+ or C#. | ||
* **slaves**: The list of indices on which you want to replicate all write operations. In order to get response times in milliseconds, we pre-compute part of the ranking during indexing. If you want to use different ranking configurations depending of the use case, you need to create one index per ranking configuration. This option enables you to perform write operations only on this index and automatically update slave indices with the same operations. | ||
* **unretrievableAttributes**: The list of attributes that cannot be retrieved at query time. This feature allows you to have attributes that are used for indexing and/or ranking but cannot be retrieved. Defaults to null. | ||
* **allowCompressionOfIntegerArray**: Allows compression of big integer arrays. We recommended enabling this feature and then storing the list of user IDs or rights as an integer array. When enabled, the integer array is reordered to reach a better compression ratio. Defaults to false. | ||
#### Query expansion | ||
* **synonyms**: (array of array of string considered as equals). For example, you may want to retrieve the **black ipad** record when your users are searching for **dark ipad**, even if the word **dark** is not part of the record. To do this, you need to configure **black** as a synonym of **dark**. For example, `"synomyms": [ [ "black", "dark" ], [ "small", "little", "mini" ], ... ]`. Synonym feature also supports multi-words expression like `"synonyms": [ ["NY", "New York"] ]` | ||
* **placeholders**: (hash of array of words). This is an advanced use case to define a token substitutable by a list of words without having the original token searchable. It is defined by a hash associating placeholders to lists of substitutable words. For example, `"placeholders": { "<streetnumber>": ["1", "2", "3", ..., "9999"]}` would allow it to be able to match all street numbers. We use the `< >` tag syntax to define placeholders in an attribute. For example: | ||
* Push a record with the placeholder: `{ "name" : "Apple Store", "address" : "<streetnumber> Opera street, Paris" }`. | ||
* Configure the placeholder in your index settings: `"placeholders": { "<streetnumber>" : ["1", "2", "3", "4", "5", ... ], ... }`. | ||
* **disableTypoToleranceOn**: (string array) Specify a list of words on which automatic typo tolerance will be disabled. | ||
* **altCorrections**: (object array) Specify alternative corrections that you want to consider. Each alternative correction is described by an object containing three attributes: | ||
* **word**: The word to correct. | ||
* **correction**: The corrected word. | ||
* **nbTypos** The number of typos (1 or 2) that will be considered for the ranking algorithm (1 typo is better than 2 typos). | ||
For example `"altCorrections": [ { "word" : "foot", "correction": "feet", "nbTypos": 1 }, { "word": "feet", "correction": "foot", "nbTypos": 1 } ]`. | ||
#### Default query parameters (can be overwritten by queries) | ||
* **minWordSizefor1Typo**: (integer) The minimum number of characters needed to accept one typo (default = 4). | ||
* **minWordSizefor2Typos**: (integer) The minimum number of characters needed to accept two typos (default = 8). | ||
* **hitsPerPage**: (integer) The number of hits per page (default = 10). | ||
* **attributesToRetrieve**: (array of strings) Default list of attributes to retrieve in objects. If set to null, all attributes are retrieved. | ||
* **attributesToHighlight**: (array of strings) Default list of attributes to highlight. If set to null, all indexed attributes are highlighted. | ||
* **attributesToSnippet**: (array of strings) Default list of attributes to snippet alongside the number of words to return (syntax is 'attributeName:nbWords').<br/>By default, no snippet is computed. If set to null, no snippet is computed. | ||
* **highlightPreTag**: (string) Specify the string that is inserted before the highlighted parts in the query result (defaults to "<em>"). | ||
* **highlightPostTag**: (string) Specify the string that is inserted after the highlighted parts in the query result (defaults to "</em>"). | ||
* **optionalWords**: (array of strings) Specify a list of words that should be considered optional when found in the query. | ||
You can easily retrieve settings or update them: | ||
ni```js | ||
index.getSettings(function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
```js | ||
index.setSettings({'customRanking': ['desc(followers)']}, function(err) { | ||
if (!err) { | ||
console.log('success'); | ||
} | ||
}); | ||
``` | ||
List indices | ||
------------- | ||
You can list all your indices along with their associated information (number of entries, disk size, etc.) with the `listIndexes` method: | ||
```js | ||
client.listIndexes(function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Delete an index | ||
------------- | ||
You can delete an index using its name: | ||
```js | ||
client.deleteIndex('contacts', function(error) { | ||
if (!err) { | ||
console.log('success'); | ||
} | ||
}); | ||
``` | ||
Clear an index | ||
------------- | ||
You can delete the index contents without removing settings and index specific API keys by using the clearIndex command: | ||
```js | ||
index.clearIndex(function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Wait indexing | ||
------------- | ||
All write operations return a `taskID` when the job is securely stored on our infrastructure but not when the job is published in your index. Even if it's extremely fast, you can easily ensure indexing is complete using the `waitTask` method on the `taskID` returned by a write operation. | ||
For example, to wait for indexing of a new object: | ||
```js | ||
var object = { | ||
firstname: 'Jimmie', | ||
lastname: 'Barninger' | ||
}; | ||
index.addObject(object, function(err, content) { | ||
index.waitTask(content.taskID, function() { | ||
console.log('object ' + content.objectID + ' indexed'); | ||
}); | ||
}); | ||
``` | ||
If you want to ensure multiple objects have been indexed, you only need check the biggest taskID. | ||
Batch writes | ||
------------- | ||
You may want to perform multiple operations with one API call to reduce latency. | ||
We expose three methods to perform batch operations: | ||
* `addObjects`: Add an array of objects using automatic `objectID` assignment. | ||
* `saveObjects`: Add or update an array of objects that contains an `objectID` attribute. | ||
* `deleteObjects`: Delete an array of objectIDs. | ||
* `partialUpdateObjects`: Partially update an array of objects that contain an `objectID` attribute (only specified attributes will be updated). | ||
Example using automatic `objectID` assignment: | ||
```js | ||
var objects = [{ | ||
firstname: 'Jimmie', | ||
lastname: 'Barninger' | ||
}, { | ||
firstname: 'Warren', | ||
lastname: 'Speach' | ||
}]; | ||
index.addObjects(objects, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example with user defined `objectID` (add or update): | ||
```js | ||
var objects = [{ | ||
firstname: 'Jimmie', | ||
lastname: 'Barninger', | ||
objectID: 'myID1' | ||
}, { | ||
firstname: 'Warren', | ||
lastname: 'Speach', | ||
objectID: 'myID2' | ||
}]; | ||
index.saveObjects(objects, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example that deletes a set of records: | ||
```js | ||
index.deleteObjects(['myID1', 'myID2'], function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Example that updates only the `firstname` attribute: | ||
```js | ||
var objects = [{ | ||
firstname: 'Jimmie', | ||
objectID: 'myID1' | ||
}, { | ||
firstname: 'Warren', | ||
objectID: 'myID2' | ||
}]; | ||
index.partialUpdateObjects(objects, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Security / User API Keys | ||
------------- | ||
The admin API key provides full control of all your indices. | ||
You can also generate user API keys to control security. | ||
These API keys can be restricted to a set of operations or/and restricted to a given index. | ||
To list existing keys, you can use `listUserKeys` method: | ||
```js | ||
// Lists global API Keys | ||
client.listUserKeys(function(err, content) { | ||
console.log(content); | ||
}); | ||
// Lists API Keys that can access only to this index | ||
index.listUserKeys(function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Each key is defined by a set of permissions that specify the authorized actions. The different permissions are: | ||
* **search**: Allowed to search. | ||
* **browse**: Allowed to retrieve all index contents via the browse API. | ||
* **addObject**: Allowed to add/update an object in the index. | ||
* **deleteObject**: Allowed to delete an existing object. | ||
* **deleteIndex**: Allowed to delete index content. | ||
* **settings**: allows to get index settings. | ||
* **editSettings**: Allowed to change index settings. | ||
* **analytics**: Allowed to retrieve analytics through the analytics API. | ||
* **listIndexes**: Allowed to list all accessible indexes. | ||
Example of API Key creation: | ||
```js | ||
// Creates a new global API key that can only perform search actions | ||
client.addUserKey(['search'], function(err, content) { | ||
console.log('Key:' + content['key']); | ||
}); | ||
// Creates a new API key that can only perform search action on this index | ||
index.addUserKey(['search'], function(err, content) { | ||
console.log('Key:' + content['key']); | ||
}); | ||
``` | ||
You can also create an API Key with advanced restrictions: | ||
* Add a validity period. The key will be valid for a specific period of time (in seconds). | ||
* Specify the maximum number of API calls allowed from an IP address per hour. Each time an API call is performed with this key, a check is performed. If the IP at the source of the call did more than this number of calls in the last hour, a 403 code is returned. Defaults to 0 (no rate limit). This parameter can be used to protect you from attempts at retrieving your entire index contents by massively querying the index. | ||
Note: If you are sending the query through your servers, you must use the `enableRateLimitForward("TheAdminAPIKey", "EndUserIP", "APIKeyWithRateLimit")` function to enable rate-limit. | ||
* Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited). This parameter can be used to protect you from attempts at retrieving your entire index contents by massively querying the index. | ||
* Specify the list of targeted indices. You can target all indices starting with a prefix or ending with a suffix using the '*' character. For example, "dev_*" matches all indices starting with "dev_" and "*_dev" matches all indices ending with "_dev". Defaults to all indices if empty or blank. | ||
```js | ||
// Creates a new global API key that is valid for 300 seconds | ||
client.addUserKey(['search'], { | ||
validity: 300 | ||
}, function(err, content) { | ||
console.log('Key:' + content['key']); | ||
}); | ||
// Creates a new index specific API key: | ||
// - valid for 300 seconds | ||
// - with a rate limit of 100 calls per hour per IP | ||
// - and a maximum of 20 hits | ||
index.addUserKey(['search'], { | ||
validity: 300, | ||
maxQueriesPerIPPerHour: 100, | ||
maxHitsPerQuery: 20 | ||
}, function(err, content) { | ||
console.log('Key:' + content['key']); | ||
}); | ||
``` | ||
Update the permissions of an existing key: | ||
```js | ||
// Update an existing global API key that is valid for 300 seconds | ||
client.updateUserKey( | ||
'myAPIKey', | ||
['search'], { | ||
validity: 300 | ||
}, function(err, content) { | ||
console.log('Key:' + content['key']); | ||
} | ||
); | ||
// Update an index specific API key: | ||
// - valid for 300 seconds | ||
// - with a rate limit of 100 calls per hour per IP | ||
// - and a maximum of 20 hits | ||
index.updateUserKey( | ||
'myAPIKey', | ||
['search'], { | ||
validity: 300, | ||
maxQueriesPerIPPerHour: 100, | ||
maxHitsPerQuery: 20 | ||
}, function(err, content) { | ||
console.log('Key:' + content['key']); | ||
} | ||
); | ||
``` | ||
Get the permissions of a given key: | ||
```js | ||
// Gets the rights of a global key | ||
client.getUserKeyACL('7f2615414bc619352459e09895d2ebda', function(err, content) { | ||
console.log(content); | ||
}); | ||
// Gets the rights of an index specific key | ||
index.getUserKeyACL('9b9335cb7235d43f75b5398c36faabcd', function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Delete an existing key: | ||
```js | ||
// Deletes a global key | ||
client.deleteUserKey('7f2615414bc619352459e09895d2ebda', function(err, content) { | ||
console.log(content); | ||
}); | ||
// Deletes an index specific key | ||
index.deleteUserKey('9b9335cb7235d43f75b5398c36faabcd', function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
You may have a single index containing per user data. In that case, all records should be tagged with their associated user_id in order to add a `tagFilters=(public,user_42)` filter at query time to retrieve only what a user has access to. If you're using the [JavaScript client](http://github.com/algolia/algoliasearch-client-js), it will result in a security breach since the user is able to modify the `tagFilters` you've set by modifying the code from the browser. To keep using the JavaScript client (recommended for optimal latency) and target secured records, you can generate a secured API key from your backend: | ||
```js | ||
// generate a public API key for user 42. Here, records are tagged with: | ||
// - 'public' if they are visible by all users | ||
// - 'user_XXXX' if they are visible by user XXXX | ||
var public_key = client.generateSecuredApiKey('YourSearchOnlyApiKey', '(public,user_42)'); | ||
``` | ||
This public API key can then be used in your JavaScript code as follow: | ||
```js | ||
var client = algoliasearch('YourApplicationID', '<%= public_api_key %>'); | ||
client.setSecurityTags('(public,user_42)'); // must be same than those used at generation-time | ||
var index = client.initIndex('indexName') | ||
index.search('something', function(err, content) { | ||
if (err) { | ||
@@ -562,54 +1237,120 @@ console.error(err); | ||
console.log(content.objectID + ": ", content); | ||
console.log(content); | ||
}); | ||
``` | ||
You can also retrieve a set of objects: | ||
You can mix rate limits and secured API keys by setting an extra `user_token` attribute both at API key generation time and query time. When set, a unique user will be identified by her `IP + user_token` instead of only by her `IP`. This allows you to restrict a single user to performing a maximum of `N` API calls per hour, even if she shares her `IP` with another user. | ||
```js | ||
// generate a public API key for user 42. Here, records are tagged with: | ||
// - 'public' if they are visible by all users | ||
// - 'user_XXXX' if they are visible by user XXXX | ||
var public_key = client.generateSecuredApiKey('YourRateLimitedApiKey', '(public,user_42)', 'user_42'); | ||
``` | ||
This public API key can then be used in your JavaScript code as follow: | ||
```js | ||
var client = algoliasearch('YourApplicationID', '<%= public_api_key %>'); | ||
// must be same than those used at generation-time | ||
client.setSecurityTags('(public,user_42)'); | ||
Security | ||
--------- | ||
// must be same than the one used at generation-time | ||
client.setUserToken('user_42'); | ||
If you're using [Per-User security](https://www.algolia.com/doc#SecurityUser) keys, you need to set the associated `tags`: | ||
var index = client.initIndex('indexName') | ||
```javascript | ||
var client = algoliasearch('ApplicationID', 'YourPublicSecuredAPIKey'); | ||
index.search('another query', function(err, content) { | ||
if (err) { | ||
console.error(err); | ||
return; | ||
} | ||
// must be the same than those used at generation-time | ||
client.setSecurityTags('(public,user_42)'); | ||
console.log(content); | ||
}); | ||
``` | ||
// If you've specified a `userToken` while generating your secured API key, you must also specified it at query-time: | ||
```javascript | ||
var client = algoliasearch('ApplicationID', 'YourPublicSecuredAPIKey'); | ||
// must be the same as the ones used at generation-time | ||
client.setSecurityTags('(public,user_42)'); | ||
Copy or rename an index | ||
------------- | ||
// must be the same as the one used at generation-time | ||
client.setUserToken('user_42'); | ||
You can easily copy or rename an existing index using the `copy` and `move` commands. | ||
**Note**: Move and copy commands overwrite the destination index. | ||
```js | ||
// Rename MyIndex in MyIndexNewName | ||
client.moveIndex('MyIndex', 'MyIndexNewName', function(err, content) { | ||
console.log(content); | ||
}); | ||
// Copy MyIndex in MyIndexCopy | ||
client.copyIndex('MyIndex', 'MyIndexCopy', function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
The move command is particularly useful if you want to update a big index atomically from one version to another. For example, if you recreate your index `MyIndex` each night from a database by batch, you only need to: | ||
1. Import your database into a new index using [batches](#batch-writes). Let's call this new index `MyNewIndex`. | ||
1. Rename `MyNewIndex` to `MyIndex` using the move command. This will automatically override the old index and new queries will be served on the new one. | ||
```js | ||
// Rename MyNewIndex in MyIndex (and overwrite it) | ||
client.moveIndex('MyNewIndex', 'MyIndex', function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Backup / Retrieve of all index content | ||
------------- | ||
You can retrieve all index content for backup purposes or for SEO using the browse method. | ||
This method retrieves 1,000 objects via an API call and supports pagination. | ||
Updating the index | ||
```js | ||
// Get first page | ||
index.browse(0, function(err, content) { | ||
console.log(content); | ||
}); | ||
// Get second page | ||
index.browse(1, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
Logs | ||
------------- | ||
In some use cases, such as an HTML5 mobile application, it may be necessary to perform updates to the index directly in JavaScript. | ||
You can retrieve the latest logs via this API. Each log entry contains: | ||
* Timestamp in ISO-8601 format | ||
* Client IP | ||
* Request Headers (API Key is obfuscated) | ||
* Request URL | ||
* Request method | ||
* Request body | ||
* Answer HTTP code | ||
* Answer body | ||
* SHA1 ID of entry | ||
Therefore, just like other languages, the JavaScript client is able to add, update, delete objects and modify index settings. | ||
You can retrieve the logs of your last 1,000 API calls and browse them using the offset/length parameters: | ||
* ***offset***: Specify the first entry to retrieve (0-based, 0 is the most recent log entry). Defaults to 0. | ||
* ***length***: Specify the maximum number of entries to retrieve starting at the offset. Defaults to 10. Maximum allowed value: 1,000. | ||
* ***onlyErrors***: Retrieve only logs with an HTTP code different than 200 or 201. (deprecated) | ||
* ***type***: Specify the type of logs to retrieve: | ||
* ***query***: Retrieve only the queries. | ||
* ***build***: Retrieve only the build operations. | ||
* ***error***: Retrieve only the errors (same as ***onlyErrors*** parameters). | ||
If you use the JavaScript client to update the index and if you are not on an `https:` website already, you must force the client to use `https:`: | ||
```js | ||
// Get last 10 log entries (default) | ||
client.getLogs(function(err, content) { | ||
console.log(content); | ||
}); | ||
```javascript | ||
<script src="//cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js"></script> | ||
<script> | ||
var client = algoliasearch('ApplicationID', 'API-Key', {protocol: 'https:'}); | ||
</script> | ||
// Get last 100 log entries | ||
client.getLogs(0, 100, function(err, content) { | ||
console.log(content); | ||
}); | ||
``` | ||
@@ -616,0 +1357,0 @@ |
@@ -1,1 +0,1 @@ | ||
"3.2.0" | ||
"3.2.1" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
816676
149
17786
1339
4
85
3
40
11
19