Lightweight fuzzy-search library with zero dependencies that implements efficient fuzzy string matching algorithms
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Dynamic collection manipulation with methods for adding, removing, and updating search data without recreating the entire index. Enables efficient real-time updates to search datasets.
Replaces the entire search dataset with new data, optionally using a pre-built index.
/**
* Updates the search collection with new data
* @param docs - New array of documents to search
* @param index - Optional pre-built FuseIndex for the new data
*/
setCollection(docs: ReadonlyArray<T>, index?: FuseIndex<T>): void;Usage Examples:
import Fuse from "fuse.js";
const fuse = new Fuse([], { keys: ["name", "email"] });
// Set initial collection
const users = [
{ name: "John Doe", email: "john@example.com" },
{ name: "Jane Smith", email: "jane@example.com" }
];
fuse.setCollection(users);
// Replace with new dataset
const newUsers = [
{ name: "Alice Johnson", email: "alice@example.com" },
{ name: "Bob Wilson", email: "bob@example.com" }
];
fuse.setCollection(newUsers);
// Use with pre-built index for performance
const index = Fuse.createIndex(["name", "email"], newUsers);
fuse.setCollection(newUsers, index);Adds a single document to the end of the search collection and updates the index.
/**
* Adds a document to the end of the collection
* @param doc - Document to add to the search collection
*/
add(doc: T): void;Usage Examples:
const fuse = new Fuse([
{ id: 1, title: "First Post", content: "Hello world" }
], { keys: ["title", "content"] });
// Add new posts dynamically
fuse.add({ id: 2, title: "Second Post", content: "More content" });
fuse.add({ id: 3, title: "Third Post", content: "Even more content" });
// Search includes new items immediately
const results = fuse.search("Second");
console.log(results[0].item.title); // "Second Post"
// Real-time updates example
function addBlogPost(post) {
fuse.add(post);
console.log(`Added post: ${post.title}`);
// Search is immediately available
const searchResults = fuse.search(post.title);
console.log(`Found ${searchResults.length} matches`);
}Removes all documents that match a predicate function and returns the removed items.
/**
* Removes documents matching the predicate function
* @param predicate - Function that returns true for items to remove
* @returns Array of removed documents
*/
remove(predicate: (doc: T, idx: number) => boolean): T[];Usage Examples:
const posts = [
{ id: 1, title: "Active Post", status: "published" },
{ id: 2, title: "Draft Post", status: "draft" },
{ id: 3, title: "Another Active", status: "published" },
{ id: 4, title: "Old Draft", status: "draft" }
];
const fuse = new Fuse(posts, { keys: ["title"] });
// Remove all draft posts
const removedDrafts = fuse.remove(post => post.status === "draft");
console.log(`Removed ${removedDrafts.length} draft posts`);
// Remove posts by ID
const removedById = fuse.remove(post => post.id === 1);
// Remove posts by title pattern
const removedByTitle = fuse.remove(post => post.title.includes("Old"));
// Complex removal conditions
const removedComplex = fuse.remove((post, index) => {
return post.status === "draft" && index > 1;
});
// Verify removal
const remainingResults = fuse.search("draft");
console.log(`Found ${remainingResults.length} draft posts`); // Should be 0Removes a document at a specific index position in the collection.
/**
* Removes the document at the specified index
* @param idx - Index of the document to remove
*/
removeAt(idx: number): void;Usage Examples:
const items = [
{ name: "First Item" },
{ name: "Second Item" },
{ name: "Third Item" }
];
const fuse = new Fuse(items, { keys: ["name"] });
// Remove the second item (index 1)
fuse.removeAt(1);
// Search to verify removal
const results = fuse.search("Second");
console.log(results.length); // Should be 0
// Remove first item (index 0)
fuse.removeAt(0);
// Only "Third Item" should remain
const remaining = fuse.search("Third");
console.log(remaining[0].item.name); // "Third Item"Common patterns for managing dynamic search collections efficiently.
Real-time Content Management:
class ContentManager {
constructor(initialContent = []) {
this.fuse = new Fuse(initialContent, {
keys: ["title", "content", "tags"],
includeScore: true,
threshold: 0.3
});
}
// Add new content
addContent(content) {
this.fuse.add(content);
console.log(`Added: ${content.title}`);
}
// Remove content by ID
removeContentById(id) {
const removed = this.fuse.remove(item => item.id === id);
return removed.length > 0;
}
// Update content (remove old, add new)
updateContent(id, newContent) {
this.removeContentById(id);
this.addContent({ ...newContent, id });
}
// Search with real-time results
search(query) {
return this.fuse.search(query);
}
// Get collection size
getSize() {
return this.fuse.getIndex().size();
}
}
// Usage
const manager = new ContentManager();
manager.addContent({ id: 1, title: "Hello World", content: "First post" });
manager.addContent({ id: 2, title: "JavaScript Tips", content: "Some tips" });
const results = manager.search("JavaScript");
console.log(results[0].item.title); // "JavaScript Tips"Batch Operations:
class BatchCollectionManager {
constructor(options) {
this.fuse = new Fuse([], options);
this.pendingAdds = [];
this.pendingRemoves = [];
}
// Queue additions
queueAdd(doc) {
this.pendingAdds.push(doc);
}
// Queue removals
queueRemove(predicate) {
this.pendingRemoves.push(predicate);
}
// Execute all pending operations
executeBatch() {
// Process removals first
this.pendingRemoves.forEach(predicate => {
this.fuse.remove(predicate);
});
// Process additions
this.pendingAdds.forEach(doc => {
this.fuse.add(doc);
});
// Clear queues
this.pendingAdds = [];
this.pendingRemoves = [];
console.log("Batch operations completed");
}
search(query) {
return this.fuse.search(query);
}
}Collection Synchronization:
class SyncedCollection {
constructor(options) {
this.fuse = new Fuse([], options);
this.itemMap = new Map(); // Track items by ID
}
// Sync with external data source
syncWithData(newData) {
const newIds = new Set(newData.map(item => item.id));
const currentIds = new Set(this.itemMap.keys());
// Remove items no longer in new data
const toRemove = [...currentIds].filter(id => !newIds.has(id));
toRemove.forEach(id => {
this.fuse.remove(item => item.id === id);
this.itemMap.delete(id);
});
// Add/update items from new data
newData.forEach(item => {
if (this.itemMap.has(item.id)) {
// Update existing
this.fuse.remove(existing => existing.id === item.id);
this.fuse.add(item);
} else {
// Add new
this.fuse.add(item);
}
this.itemMap.set(item.id, item);
});
console.log(`Synced ${newData.length} items`);
}
search(query) {
return this.fuse.search(query);
}
getItemCount() {
return this.itemMap.size;
}
}Best practices for efficient collection management.
Usage Examples:
// Efficient for small, frequent updates
const realtimeFuse = new Fuse(initialData, options);
realtimeFuse.add(newItem); // O(1) for index update
realtimeFuse.removeAt(0); // O(n) for index shifting
// For large batch updates, consider rebuilding
if (updatesCount > dataset.length * 0.1) {
// Rebuild entire collection if updates exceed 10% of data
const newIndex = Fuse.createIndex(keys, newDataset);
fuse.setCollection(newDataset, newIndex);
} else {
// Apply individual updates
updates.forEach(update => {
if (update.type === "add") {
fuse.add(update.item);
} else if (update.type === "remove") {
fuse.removeAt(update.index);
}
});
}
// Memory management for large collections
const largeFuse = new Fuse([], options);
// Add items in chunks to avoid blocking
async function addItemsInChunks(items, chunkSize = 1000) {
for (let i = 0; i < items.length; i += chunkSize) {
const chunk = items.slice(i, i + chunkSize);
chunk.forEach(item => largeFuse.add(item));
// Allow other operations to proceed
await new Promise(resolve => setTimeout(resolve, 0));
}
}