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