or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

collection-management.mdcore-search.mdextended-search.mdindex-management.mdindex.md
tile.json

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