{"id":20449811,"url":"https://github.com/yann510/ss-search","last_synced_at":"2025-04-05T05:09:33.298Z","repository":{"id":38174752,"uuid":"251494069","full_name":"yann510/ss-search","owner":"yann510","description":"The most basic, yet powerful text search.","archived":false,"fork":false,"pushed_at":"2025-02-11T12:21:13.000Z","size":56733,"stargazers_count":54,"open_issues_count":4,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-29T04:12:01.441Z","etag":null,"topics":["array","browser","easy","fast","full-text","index","javascript","node","nodejs","object","search","simple","ss-search","stupid","text","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yann510.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-31T03:46:11.000Z","updated_at":"2025-02-04T19:58:11.000Z","dependencies_parsed_at":"2024-01-20T03:31:00.553Z","dependency_job_id":"a4df99b7-5150-4f84-b320-d1525705e0ac","html_url":"https://github.com/yann510/ss-search","commit_stats":{"total_commits":133,"total_committers":5,"mean_commits":26.6,"dds":"0.30827067669172936","last_synced_commit":"e7710672337ac6123b9417f68f8fa8078e2e5f23"},"previous_names":[],"tags_count":57,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann510%2Fss-search","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann510%2Fss-search/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann510%2Fss-search/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann510%2Fss-search/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yann510","download_url":"https://codeload.github.com/yann510/ss-search/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289429,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["array","browser","easy","fast","full-text","index","javascript","node","nodejs","object","search","simple","ss-search","stupid","text","typescript"],"created_at":"2024-11-15T10:44:56.934Z","updated_at":"2025-04-05T05:09:33.279Z","avatar_url":"https://github.com/yann510.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![npm](https://img.shields.io/npm/v/ss-search?style=flat-square)\n![npm bundle size](https://img.shields.io/bundlephobia/minzip/ss-search?style=flat-square)\n![build](https://github.com/yann510/ss-search/actions/workflows/publish-package.yml/badge.svg)\n![Coveralls github](https://img.shields.io/coveralls/github/yann510/ss-search?style=flat-square)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)](http://commitizen.github.io/cz-cli/)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release)\n\n# s(imply)s(tupid)-search\n\n### The most basic, yet powerful text search.\n\n### Stop searching, start finding.\n\n- **Ease of Use**: Get appropriate results instantly without any configuration.\n- **Local Array Search**: Effortlessly search through a local array of objects.\n- **Automatic Indexing**: No manual indexing required.\n- **Precision**: Always get exactly what you're looking for.\n- **Lightweight**: Depends on just 5 lodash functions for a minimized size after tree shaking.\n\n## Demo\n\n![](demo.gif)\n\nStill not convinced? Experience its power firsthand with this interactive [demo](https://ss-search.netlify.app/).\n\n### Benchmark\n\nHow does it compare to other search libraries? Test out for yourself with this interactive [benchmark](https://ss-search.netlify.app/benchmark) ;)\n\n## Install\n\nss-search is available on [npm](https://www.npmjs.com/package/ss-search). Install it with:\n\n`npm install ss-search`\n\n## Usage\n\n### Basic\n\n```javascript\nimport { search } from 'ss-search'\n\nconst data = [\n  {\n    number: 1,\n    text: 'A search function should be fast',\n  },\n  {\n    number: 2,\n    text: 'A search function should provide accurate results',\n  },\n]\nconst searchKeys = ['text']\nconst searchText = 'fast search'\n\nconst results = search(data, searchKeys, searchText)\n// results: [{ number: 1, text: \"A search function should be fast\" }]\n```\n\nIt's that straightforward. No configurations, it just works.\n\n### Data Types\n\nAlmost all data types are supported [boolean, number, string, object, array].\n\n```javascript\n// This dataset will be used as a common starting point for our type examples\nconst data = [\n  {\n    boolean: true,\n    number: 1,\n    string: 'search',\n    object: { nestedProperty: 'nested value' },\n    array: ['value1', 'value2'],\n    arrayObjects: [{ arrayObjectProperty: 'array object value' }],\n  },\n]\n```\n\n#### Boolean\n\n```javascript\nconst results = search(data, ['boolean'], 'true')\n// results: will return our original dataset\n```\n\n#### Number\n\n```javascript\nconst results = search(data, ['number'], '1')\n// results: will return our original dataset\n```\n\n#### String\n\n```javascript\nconst results = search(data, ['string'], 'search')\n// results: will return our original dataset\n```\n\n#### Object\n\nProviding a key which refers to an object will stringify that object using JSON.stringify\n\n```javascript\nconst results = search(data, ['object'], 'property')\n// results: will return our original dataset as it matches the property key \"nestedProperty\" of our object\n```\n\nIf you want to access a nested property of an object to extract only a single value\n\n```javascript\nconst results = search(data, ['object.nestedProperty'], 'property')\n// results: will return an empty array as we extracted the value of our nested object\n// if we had searched for \"nested value\" we would of had the original dataset\n```\n\n#### Array\n\nProviding a key which refers to an array will stringify that array using JSON.stringify\n\n```javascript\nconst results = search(data, ['array'], 'value2')\n// results: will return our original dataset\n```\n\nIf you have an array of objects on which you want to search all properties\n\n```javascript\nconst results = search(data, ['arrayObjects'], 'arrayObjectProperty')\n// results: will return an our original dataset as it's treated just like a regular array\n// thus the arrayObjectProperty is part of the searchable text\n```\n\nIf you have an array of objects where you want only specific properties to be searchable\n\n```javascript\nconst results = search(data, ['arrayObjects[arrayObjectProperty]'], 'arrayObjectProperty')\n// results: will return an empty array as we extracted the value of our nested array of objects\n// if we had searched for \"value object\" we would of had the original dataset\n```\n\n### Options for the `search` function\n\nCustomize your search experience using the following options:\n\n| Option parameter | Value     | Description                                                                                                                                                                                                                                                                                                                   |\n| ---------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `withScore`      | `true`    | When set to `true`, the search function will return an array of objects, each containing the matched element and its corresponding score. The score represents how closely the element matches the search text, with a higher score indicating a closer match. Even if the search doesn't match, it will return a score of 0. |\n| `withScore`      | `false`   | When set to `false` or not provided, the function will return an array of matched elements without their scores.                                                                                                                                                                                                              |\n| `cacheKey`       | `unknown` | The cacheKey is required if you dynamically update the `searchableKeys` as the memoization function will use the elements array by default to memoize the search tokens.                                                                                                                                                      |\n\n### Example Usage\n\nWithout `withScore` option:\n\n```javascript\nconst data = [{ name: 'John' }, { name: 'Jane' }, { name: 'Doe' }]\nconst result = search(data, ['name'], 'John')\nconsole.log(result) // [{ name: 'John' }]\n```\n\nWith `withScore` option:\n\n```javascript\nconst data = [{ name: 'John' }, { name: 'Jane' }, { name: 'Doe' }]\nconst result = search(data, ['name'], 'John', { withScore: true })\nconsole.log(result)\n// [\n//  { element: { name: 'John' }, score: 1 },\n//  { element: { name: 'Jane' }, score: 0 },\n//  { element: { name: 'Doe' }, score: 0 }\n// ]\n```\n\nWhen updating the `searchableKeys` dynamically, you need to provide a `cacheKey`:\n\n```javascript\nconst data = [\n  { name: 'John', age: 50 },\n  { name: 'Jane', age: 40 },\n]\nconst result1 = search(data, ['name'], 'John', { cacheKey: 'name' })\nconst result2 = search(data, ['age'], 40, { cacheKey: 'age' })\n// result1: [{ name: 'John', age: 50 }]\n// result2: [{ name: 'Jane', age: 40 }]\n\n// If you do not manually update the cache-key, your second search would have used \"name\" as the `searchKeys` and returned an empty array\n```\n\n![](benchmark.gif)\n\n### Developing\n\nTo better manage dependencies across the monorepo I'm using [NX](https://nx.dev/).\n\nInstall dependencies:\n`npm i`\n\nStart the web-app:\n`npm run web-app:serve`\n\nTest the library:\n`npm run test:all`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyann510%2Fss-search","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyann510%2Fss-search","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyann510%2Fss-search/lists"}