node-suggestive-search
v1.10.6
Published
A node module to help type-ahead and dropdown search boxes and also correct misspelled searches (did you mean?).
Downloads
48
Maintainers
Readme
Node suggestive search
Don't let spelling mistakes prevent your users from finding what they were looking for! This node module was built to help type-ahead and dropdown search boxes and also correct misspelled searches (did you mean?).
This module is compatible with:
- Redis Node.JS Client 2.8.0, Client to connect with Redis https://www.npmjs.com/package/redis
- MongoDB Node.JS Driver 2.2.19, Driver to connect with MongoDB http://mongodb.github.io/node-mongodb-native/
- NeDB 1.8.0, The JavaScript Database from Louis Chatriot https://github.com/louischatriot/nedb
Installation, tests
Module name on npm is "node-suggestive-search".
npm install node-suggestive-search --save # Install the latest version in your project
Example of usage
https://node-suggestive-search.herokuapp.com
API
- Setting options
- Loading a database
- Searching for items
- Getting words suggestions
- Getting items suggestions
- Insert items
- Remove items
Setting options
This module supports Redis, MongoDB and NeDB but you can use an in-memory volatile cache.
Configuration without database (in-memory):
var nss = require('node-suggestive-search').init();
Configuration without database with cache (in-memory):
var nss = require('node-suggestive-search').init({ cache: true });
Configuration using Redis:
var nss = require('node-suggestive-search').init(
{
dataBase: "redis",
redisDatabase: "redis://localhost:6379",
cache: true
});
Configuration using MongoDB:
var nss = require('node-suggestive-search').init(
{
dataBase: "mongodb",
mongoDatabase: "mongodb://127.0.0.1:27017/nodeSugestiveSearch",
cache: true
});
Configuration using NeDB with a datafile:
var nss = require('node-suggestive-search').init(
{
dataBase: "nedb",
neDbDataPath: "dataFolder",
neDbInMemoryOnly: false,
cache: true
});
Configuration using NeDB without a datafile (in-memory):
var nss = require('node-suggestive-search').init(
{
dataBase: "nedb",
neDbDataPath: "",
neDbInMemoryOnly: true,
cache: false
});
There is also an option to include stop-words:
var nss = require('node-suggestive-search').init(
{
stopWords: ["1033", "1046", ..., __dirname + "\\yourOwnStopWords.json"]
});
//current built-in available stopwords dictionary
//1033 - en-us - English - United States
//1036 - fr-fr - French - France
//1040 - it-it - Italian - Italy
//1046 - pt-br - Portuguese - Brazil
//1048 - ro - Romanian - Romania
//2057 - en-gb - English - Great Britain
//2070 - pt-pt - Portuguese - Portugal
The "cache" option enables an in-memory copy of the data structure boosting the performance. Turn off this option if you have more than one instance accessing the same database.
Loading a database
Build a dictionary composed by items and words that need to be searched.
Example of a JSON to be imported (Items.json):
[
{
"itemName":"WHISKY RED LABEL",
"itemId":"1",
"keywords":"FANCY"
},
{
"itemName":"WHISKY BLACK LABEL",
"itemId":"2",
"keywords":"EXPENSIVE"
},
{
"itemName":"BLACK FOREST LABELY HAM L/S",
"itemId":"3"
},
{
"itemName":"PESTO PARMESAN HAM",
"itemId":"4"
},
{
"itemName":"DELI SWEET SLICE SMOKED HAM",
"itemId":"5"
}
]
Load the JSON from file
//you can change the charset to match your file
nss.loadJson("Items.json", "utf8").then(data => {
// response: { words: 17, items: 5, timeElapsed: '4ms' }
});
Load the JSON from file with your properties names
nss.loadJson("Items.json", "utf8", "itemId", "itemName", "keywords").then(data => {
// response: { words: 17, items: 5, timeElapsed: '3ms' }
});
Load the JSON from string
let jSonString = `[{"itemName":"WHISKY RED LABEL", "itemId":"1", "keywords": "fancy"},{
"itemName":"WHISKY BLACK LABEL", "itemId":"2"}]`;
nss.loadJsonString(jSonString).then(data => {
// response: { words: 5, items: 2, timeElapsed: '1ms' }
});
Load the JSON from string with additional fields (price, popularity and thumbImg). You can insert any additional field excluding itemId, itemName and keywords.
let jSonString = `[{"itemName":"WHISKY RED LABEL", "itemId":"1", "keywords":"fancy", "price":25.57, "popularity":1, "thumbImg":"whisky-red-label.png"},{
"itemName":"WHISKY BLACK LABEL", "itemId":"2", "price":19.99, "popularity":0.9, "thumbImg":"whisky-black-label.png"}]`;
nss.loadJsonString(jSonString).then(data => {
// response: { words: 5, items: 2, timeElapsed: '2ms' }
});
Load the JSON from string with your properties names
let jSonString = `[{"nm":"WHISKY RED LABEL", "id":"1", "kw": "fancy"},{
"nm":"WHISKY BLACK LABEL", "id":"2"}]`;
nss.loadJsonString(jSonString, "id", "nm", "kw").then(data => {
// response: { words: 5, items: 2, timeElapsed: '2ms' }
});
Load the JSON from string with your properties names and additional fields (price, popularity and thumbImg). You can insert any additional field excluding itemId, itemName and keywords.
let jSonString = `[{"nm":"WHISKY RED LABEL", "id":"1", "kw":"fancy", "price":25.57, "popularity":1, "thumbImg":"whisky-red-label.png"},{
"nm":"WHISKY BLACK LABEL", "id":"2", "price":19.99, "popularity":0.9, "thumbImg":"whisky-black-label.png"}]`;
nss.loadJsonString(jSonString, "id", "nm", "kw").then(data => {
// response: { words: 5, items: 2, timeElapsed: '2ms' }
});
Searching for items
Getting itemsId from searched words.
Examples of how to call the api and responses:
nss.query("whisky").then(data => {
//response: { query: 'whisky', words: [ 'whisky' ], missingWords: [], expressions: [], missingExpressions: [], itemsId: [ '1', '2' ], timeElapsed: '1ms' }
});
//did you mean search result with misspelled search criteria
nss.query("wisk").then(data => {
//response: { query: 'wisk', words: [ 'whisky' ], missingWords: ['wisk'], expressions: [], missingExpressions: [], itemsId: [ '1', '2' ], timeElapsed: '1ms' }
});
//did you mean search result with misspelled search criteria
nss.query("wisk read lbel").then(data => {
//response: { query: 'Wisk Read Labl', words: [ 'Whisky', 'Red', 'Label' ], missingWords: ['Wisk', 'Read', 'Labl'], expressions: [], missingExpressions: [], itemsId: [ '1' ], timeElapsed: '2ms' }
});
//query with paramenter returnItemsJson = true
nss.query("whisky", true).then(data => {
/*response: { query: 'whisky', words: [ 'whisky' ], missingWords: [], expressions: [], missingExpressions: [],
[
{ itemName: 'WHISKY RED LABEL', itemId: '1', keywords: 'fancy' },
{ itemName: 'WHISKY BLACK LABEL', itemId: '2' }
],
timeElapsed: '1ms' }
*/
});
//query with paramenter returnItemsJson = true and ordering by popularity, desc using an object on a database loaded with additional fields
let orderByObject = {field: "popularity", direction: "desc"};
nss.query("whisky", true, orderByObject).then(data => {
/*response: { query: 'whisky', words: [ 'whisky' ], missingWords: [], expressions: [], missingExpressions: [],
[
{ itemName: 'WHISKY RED LABEL', itemId: '1', keywords: 'fancy', price: 25.57, popularity: 1, thumbImg: 'whisky-red-label.png' },
{ itemName: 'WHISKY BLACK LABEL', itemId: '2', price: 19.99, popularity: 0.9, thumbImg: 'whisky-black-label.png' }
],
timeElapsed: '1ms' }
*/
});
//query with paramenter returnItemsJson = true and ordering by popularity, desc using a function on a database loaded with additional fields
let orderByFunc = ((x, y) => { return x.popularity < y.popularity; });
nss.query("whisky", true, orderByFunc).then(data => {
/*response: { query: 'whisky', words: [ 'WHISKY' ], missingWords: [], expressions: [], missingExpressions: [],
[
{ itemName: 'WHISKY RED LABEL', itemId: '1', keywords: 'fancy', price: 25.57, popularity: 1, thumbImg: 'whisky-red-label.png' },
{ itemName: 'WHISKY BLACK LABEL', itemId: '2', price: 19.99, popularity: 0.9, thumbImg: 'whisky-black-label.png' }
],
timeElapsed: '1ms' }
*/
});
//quoted search criteria
nss.query("'red label'").then(data => {
//response: { query: '\'RED LABEL\'', words: [ 'RED', 'LABEL' ], missingWords: [], expressions: [ 'RED LABEL' ], missingExpressions: [], itemsId: [ '1' ], timeElapsed: '1ms' }
});
//quoted search criteria
nss.query("'label red'").then(data => {
//response: { query: '\'label red\'', words: [ 'label', 'red' ], missingWords: [], expressions: [], missingExpressions: [ 'label red' ], itemsId: [ '1' ], timeElapsed: '2ms' }
});
//dashed search criteria
nss.query("Red-Blood").then(data => {
//response: { query: 'Red-Blood', words: [ 'Red' ], missingWords: [ 'Blood' ], expressions: [], missingExpressions: [ 'Red-Blood' ], itemsId: [ '1' ], timeElapsed: '2ms' }
});
//slashed search criteria
nss.query("HAM L/S").then(data => {
//response: { query: 'HAM L/S', words: [ 'HAM', 'L', 'S' ], missingWords: [], expressions: [ 'L/S' ], missingExpressions: [], itemsId: [ '3' ], timeElapsed: '2ms' }
});
//double quoted search criteria
nss.query("\"HAM L/S\"").then(data => {
//response: { query: '"HAM L/S"', words: [ 'HAM', 'L', 'S' ], missingWords: [], expressions: [ 'HAM L/S' ], missingExpressions: [], itemsId: [ '3' ], timeElapsed: '2ms' }
});
Getting words suggestions
Getting words suggestions to fill dropdown boxes or type-ahead text fields.
Examples of how to call the api and responses:
nss.getSuggestedWords("La").then(data => {
//response: { suggestions: [ 'Label', 'Labely' ], timeElapsed: '1ms' }
});
nss.getSuggestedWords("whi").then(data => {
//response: { suggestions: [ 'whisky label', 'whisky red', 'whisky black' ], timeElapsed: '1ms' }
});
nss.getSuggestedWords("whisky re").then(data => {
//response: { suggestions: [ 'whisky red' ], timeElapsed: '2ms' }
});
Getting items suggestions
Getting items suggestions to fill dropdown boxes or type-ahead text fields.
Examples of how to call the api and responses:
nss.getSuggestedItems("PARME").then(data => {
//response: { items: [ { itemId: '4', itemName: 'PESTO PARMESAN HAM' } ], timeElapsed: '2ms' }
});
nss.getSuggestedItems("Whisky fancy").then(data => {
//response: { items: [ { itemId: '1', itemName:'WHISKY RED LABEL' } ], timeElapsed: '1ms' }
});
nss.getSuggestedItems("whisky re").then(data => {
//response: { items:[ { itemId: '1', itemName: 'WHISKY RED LABEL' } ], timeElapsed: '1ms' }
});
nss.getSuggestedItems("whisky label").then(data => {
//response: { items: [ {itemId: '1', itemName: 'WHISKY RED LABEL' }, { itemId: '2', itemName: 'WHISKY BLACK LABEL' } ], timeElapsed: '2ms' }
});
//get one item suggestions ordering by price, asc using a function and omitting the direction.
let orderByObject = {field: "price"};
nss.getSuggestedItems("whisky label", 1, orderByObject).then(data => {
//response: { items: [ { itemName: 'WHISKY BLACK LABEL', itemId: '2', price: 19.99, popularity: 0.9, thumbImg: 'whisky-black-label.png' } ], timeElapsed: '2ms' }
});
//get one item suggestions ordering by price, asc using a function.
let orderByFunc = ((x, y) => { return x.price > y.price; });
nss.getSuggestedItems("whisky label", 1, orderByFunc).then(data => {
//response: { items: [ { itemName: 'WHISKY BLACK LABEL', itemId: '2', price: 19.99, popularity: 0.9, thumbImg: 'whisky-black-label.png' } ], timeElapsed: '2ms' }
});
Insert items
Insert a new item into the database.
Examples of how to call the api and responses:
let newItem = {
"itemId": "VODKA ABSOLUT",
"itemName": "6",
"keywords": "Keyword1, keyword2..."
};
nss.insertItem(newItem).then(data => {
//response: { timeElapsed: '2ms' }
});
Insert an item with your properties names.
let newItem = {
"id": "VODKA ABSOLUT",
"nm": "6",
"kw": "Keyword1, keyword2..."
};
nss.insertItem(newItem, "id", "nm", "kw").then(data => {
//response: { timeElapsed: '2ms' }
});
Insert an item with additional fields (price, popularity and thumbImg). You can insert any additional field excluding itemId, itemName and keywords.
let newItem = {
"itemId": "VODKA ABSOLUT",
"itemName": "6",
"keywords": "Keyword1, keyword2...",
"price": 25.57,
"popularity": 1,
"thumbImg": "vodka-absolute.png"
};
nss.insertItem(newItem).then(data => {
//response: { timeElapsed: '2ms' }
});
Remove items
Remove an item from the database.
Examples of how to call the api and responses:
let itemId = "6";
nss.removetItem(itemId).then(data => {
//response: { timeElapsed: '2ms' }
});
Roadmap
- Catalog (several dictionaries)
- More databases support
- Inject your database plugin
- Browser version.
- Translate JS to TS
Pull requests
If you submit a pull request, thanks! There are a couple of rules to follow to make it manageable:
- The pull request should be atomic, i.e. contain only one feature. If it contains more, please submit multiple pull requests.
- Please stick to the current coding style. It's important that the code uses a coherent style for readability.
- Update the readme accordingly.
- Last but not least: The goal here is simplicity.
Bug reporting guidelines
If you report a bug, thank you! That said for the process to be manageable please strictly adhere to the following guidelines. I'll not be able to handle bug reports that don't:
- Your bug report should be a self-containing project with a package.json for any dependencies you need. I need to run through a simple
npm install; node bugreport.js
. - It should use assertions to showcase the expected vs actual behavior.
- Simplify as much as you can. Strip all your application-specific code.
- Please explain precisely in the issue.
- The code should be Javascript.
Donations
Please consider donating some if your app is successful or you learned something valuable here.
Keep in mind that I am maintaining this repository on my free time so thank you for considering a donation. :+1: