CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-fuse-js

Lightweight fuzzy-search library with zero dependencies that implements efficient fuzzy string matching algorithms

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

collection-management.mddocs/

Collection Management

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.

Capabilities

Set Collection

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);

Add Document

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`);
}

Remove Documents

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 0

Remove at Index

Removes 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"

Dynamic Collection Patterns

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;
  }
}

Performance Considerations

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));
  }
}

docs

collection-management.md

core-search.md

extended-search.md

index-management.md

index.md

tile.json