Utils (@pim.sk/utils)

fulltext-filter

Fulltext search over an array of objects. Case-insensitive, multi-word AND logic, optional diacritics normalization and field scoping.
import { fulltextFilter } from '@pim.sk/utils/fulltext-filter.mjs'

Usage

fulltextFilter( items, searchText )

Case-insensitive search across all object fields. Space between words acts as AND operator — all words must match.

const items = [
    { id: 1, code: "admin",   name: "Administration",  desc: "System management"  },
    { id: 2, code: "eshop",   name: "E-shop",          desc: "Online store"       },
    { id: 3, code: "catalog", name: "Catalog",         desc: "Product listing"    },
    { id: 4, code: "blog",    name: "Blog",            desc: "Articles and posts" },
    { id: 5, code: "users",   name: "User management", desc: "Accounts and roles" },
    { id: 6, code: "buyers",  name: "Buyers",          desc: "Administrative management" },
    { id: 7, code: "user",    name: "Person",          desc: "Person roles"      },
]
fulltextFilter(items, "admin")
// → [{ id:1, code:"admin", name:"Administration", ... }]

fulltextFilter(items, "online store")
// → [{ id:2, ... }]  (both words must match)

AND search — space = AND operator

Each word separated by a space must be found somewhere in the object. All words must match — if any word is missing, the item is excluded.

"management"        → 3 results  (id:1, id:5, id:6)
"admin management"  → 2 results  (id:1 code:"admin" + desc:"System management"
                                   id:6 desc:"Administrative management")
"user management"   → 1 result   (id:5 name:"User management")
"user roles"        → 2 result   (id:5 name:"User management" + desc:"Accounts and roles")
"user xyz"          → 0 results  ("xyz" not found anywhere)
fulltextFilter(items, "admin management")
// word "admin"      found in: id:1.code, id:6.desc
// word "management" found in: id:1.desc, id:5.name, id:6.desc
// AND  → id:1 ✓  id:6 ✓

OR search — comma = OR operator

Comma separates independent search groups. Item matches if ANY group fully matches (AND logic still applies within each group).

"eshop,catalog"           → 2 results  (id:2 OR id:3)
"eshop,user management"   → 2 results  (id:2) OR (id:5 — "user" AND "management")
"online,product listing"  → 2 results  (id:2 — "online") OR (id:3 — "product" AND "listing")
"blog,xyz"                → 1 result   (id:4 — "blog") OR ("xyz" — no match)
fulltextFilter(items, "eshop,catalog")
// OR group 1: "eshop"   → id:2 ✓
// OR group 2: "catalog" → id:3 ✓

fulltextFilter(items, "eshop,user management")
// OR group 1: "eshop"              → id:2 ✓
// OR group 2: "user" AND "management" → id:5 ✓

options.fields

Limit search to specific fields only. Without fields option, all fields are searched.

options.fields = ["name", "desc"]
// search only in "name" and "desc"
fulltextFilter(items, "admin", { fields: ["name", "desc"] })
// → []  — "admin" is in code field, not in name/desc

fulltextFilter(items, "system", { fields: ["name", "desc"] })
// → [{ id:1, ... desc:"System management" }]

options.bAccent

By default diacritics are ignored (a = á, e = é ...). Set bAccent: false to enforce exact accent matching.

const items = [
    { id: 1, name: "Katalog"  },  // no accent
    { id: 2, name: "Katalóg" },  // with accent
]


fulltextFilter(items, "katalog")                    // bAccent: true (default)
// → both items found  (a = a)

fulltextFilter(items, "katalog", { bAccent: false })
// → only id:1 — exact match required

options.minSearchLength

Minimum number of characters before filtering starts. Shorter input returns the full array unchanged.

options.minSearchLength = 3
fulltextFilter(items, "ad",  { minSearchLength: 3 })
// → full array (too short, no filter applied)

fulltextFilter(items, "adm", { minSearchLength: 3 })
// → [{ id:1, code:"admin", ... }]
v 1.1.2