Utility Methods¶
Utility methods for updating, deleting, debugging, and other collection operations. These methods provide practical functionality for data manipulation and development workflows.
Overview¶
Utility methods fall into four categories:
Mutation Methods (modify collection): - update() - Update matching elements - delete() - Remove matching elements - shuffle() - Randomize order
Iteration Methods: - each() - Iterate with early exit
Randomization Methods: - random() - Get random elements
Debugging Methods: - dump() - Print and continue - dd() - Print and exit - stringify() - Convert to JSON
update()¶
update(set: T): number¶
update(where: Query<V>, set: T): number¶
Updates elements that match criteria. This method mutates the collection.
Parameters:
| Parameter | Type | Description |
|---|---|---|
where | Query<V> | Query object to match elements (optional - if omitted, updates all) |
set | T | Object with fields to update (supports template strings) |
Returns: number - Count of updated elements
Example - Update all elements:
const users = new Collection([
{ id: 1, name: 'Alice', status: 'pending' },
{ id: 2, name: 'Bob', status: 'pending' }
]);
const count = users.update({ status: 'active' });
// count = 2
// All users now have status: 'active'
Example - Update matching elements:
const orders = new Collection([
{ id: 1, status: 'pending', total: 100 },
{ id: 2, status: 'pending', total: 200 },
{ id: 3, status: 'completed', total: 150 }
]);
const updated = orders.update(
{ status: 'pending' },
{ status: 'processing', processedAt: new Date() }
);
// updated = 2 (only pending orders updated)
Example - Template strings for field references:
const users = new Collection([
{ id: 1, email: 'old@example.com', name: 'Alice' }
]);
users.update(
{ email: /old@example\.com/ },
{
email: 'new@example.com',
prevEmail: '${email}' // Template: saves old email value
}
);
// Result: { id: 1, email: 'new@example.com', prevEmail: 'old@example.com', name: 'Alice' }
Example - Conditional updates:
const products = new Collection([
{ id: 1, price: 100, discount: 0 },
{ id: 2, price: 200, discount: 0 },
{ id: 3, price: 50, discount: 0 }
]);
// Apply discount to expensive items
products.update(
{ price: { $gte: 100 } },
{ discount: 0.15 }
);
Example - Bulk status change:
// Mark all inactive users as deleted
const deletedCount = users.update(
{ active: false },
{ deleted: true, deletedAt: new Date() }
);
console.log(`Marked ${deletedCount} users as deleted`);
Example - Complex query updates:
// Update users with expired subscriptions
const expiredCount = users.update(
{
subscription: { $exists: true },
'subscription.expiresAt': { $lt: Date.now() }
},
{
'subscription.status': 'expired',
'subscription.expiredAt': Date.now()
}
);
Mutability Note:
const original = new Collection([
{ id: 1, status: 'pending' }
]);
original.update({ status: 'active' });
console.log(original);
// [{ id: 1, status: 'active' }] - Modified in place
To update without mutation:
const updated = original.collect().update({ status: 'active' });
console.log(original); // Unchanged
delete()¶
delete(where: Query<V>): number¶
Removes elements that match query criteria. This method mutates the collection.
Parameters:
| Parameter | Type | Description |
|---|---|---|
where | Query<V> | Query object to match elements for deletion |
Returns: number - Count of deleted elements
Example - Delete matching elements:
const users = new Collection([
{ id: 1, name: 'Alice', deleted: false },
{ id: 2, name: 'Bob', deleted: true },
{ id: 3, name: 'Charlie', deleted: false }
]);
const removedCount = users.delete({ deleted: true });
// removedCount = 1
// users now has 2 items (Bob removed)
Example - Delete with complex query:
const products = new Collection([
{ id: 1, stock: 0, discontinued: true },
{ id: 2, stock: 10, discontinued: false },
{ id: 3, stock: 0, discontinued: false }
]);
// Remove discontinued items with no stock
const removed = products.delete({
stock: 0,
discontinued: true
});
// removed = 1
Example - Delete by date:
const sessions = new Collection([
{ id: 1, expiresAt: new Date('2024-01-01') },
{ id: 2, expiresAt: new Date('2025-01-01') },
{ id: 3, expiresAt: new Date('2024-06-01') }
]);
// Delete expired sessions
const expired = sessions.delete({
expiresAt: { $lt: Date.now() }
});
Example - Cleanup pattern:
// Remove test data and inactive users
const cleaned = users
.delete({ email: { $regex: /@test\.com$/ } }) // Remove test emails
+ users.delete({ lastLogin: { $exists: false } }); // Remove never logged in
console.log(`Cleaned ${cleaned} users`);
Example - Conditional deletion:
const tasks = new Collection([
{ id: 1, status: 'completed', completedAt: new Date('2024-01-01') },
{ id: 2, status: 'completed', completedAt: new Date('2024-12-01') },
{ id: 3, status: 'pending', completedAt: null }
]);
// Delete old completed tasks (> 6 months)
const sixMonthsAgo = Date.now() - (6 * 30 * 24 * 60 * 60 * 1000);
tasks.delete({
status: 'completed',
completedAt: { $lt: sixMonthsAgo }
});
Mutability Note:
const original = new Collection([1, 2, 3, 4, 5]);
original.delete({ $gte: 3 });
console.log(original);
// [1, 2] - Elements >= 3 removed from original
To delete without mutation:
const filtered = original.not({ $gte: 3 }); // Use not() instead
console.log(original); // Unchanged
Difference from filter():
const items = new Collection([1, 2, 3, 4, 5]);
// filter() - immutable, returns new collection
const filtered = items.filter({ $lt: 3 });
console.log(items.length); // 5 (unchanged)
console.log(filtered.length); // 2
// delete() - mutable, modifies original
const deleted = items.delete({ $gte: 3 });
console.log(items.length); // 2 (modified)
console.log(deleted); // 3 (count of deleted)
each()¶
each(fn: (item: T, index: number, arr: this) => any): this¶
Iterates over collection executing callback for each element. Return false to stop iteration early.
Parameters:
| Parameter | Type | Description |
|---|---|---|
fn | (item: T, index: number, arr: this) => any | Callback executed for each element |
Returns: this - The collection (for chaining)
Example - Basic iteration:
const users = new Collection([
{ name: 'Alice', score: 95 },
{ name: 'Bob', score: 87 },
{ name: 'Charlie', score: 92 }
]);
users.each((user, index) => {
console.log(`${index + 1}. ${user.name}: ${user.score}`);
});
// 1. Alice: 95
// 2. Bob: 87
// 3. Charlie: 92
Example - Early exit:
let sum = 0;
users.each((user, index) => {
if (user.score < 90) {
return false; // Stop iteration
}
sum += user.score;
});
// Stops at Bob (score 87), sum = 95 (only Alice)
Example - Process until condition:
const orders = new Collection([...]);
let total = 0;
const limit = 1000;
orders.each(order => {
if (total >= limit) {
return false; // Stop when limit reached
}
total += order.amount;
});
console.log(`Processed $${total}`);
Example - Find first match:
let found: User | undefined;
users.each(user => {
if (user.email === 'target@example.com') {
found = user;
return false; // Stop when found
}
});
Example - Side effects with chaining:
users
.filter({ active: true })
.each(user => {
sendEmail(user.email);
})
.each((user, index) => {
console.log(`Sent email ${index + 1} of ${users.length}`);
});
Difference from forEach():
// forEach() - cannot stop early
users.forEach(user => {
console.log(user);
// No way to break
});
// each() - can stop early
users.each(user => {
console.log(user);
if (condition) return false; // Stops iteration
});
Note: Returns collection for chaining:
const result = users
.each(user => trackView(user))
.filter({ verified: true })
.sort('name', 'asc');
random()¶
random(length?: number): T[]¶
Returns random elements from the collection. Does not mutate the collection.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
length | number | Infinity | Number of random elements to return |
Returns: T[] - Array of random elements (plain array, not Collection)
Example - Get single random element:
const users = new Collection([...100 users...]);
const randomUser = users.random(1)[0];
console.log(randomUser);
Example - Get multiple random elements:
const products = new Collection([...50 products...]);
const featured = products.random(5);
// Returns 5 random products
Example - Get all in random order:
const items = new Collection([1, 2, 3, 4, 5]);
const shuffled = items.random();
// Returns all items in random order, e.g., [3, 1, 5, 2, 4]
Example - Random sampling:
// Get 10% sample for testing
const sampleSize = Math.ceil(users.length * 0.1);
const sample = users.random(sampleSize);
Example - Random winners:
const entries = new Collection([...contest entries...]);
const winners = entries
.filter({ eligible: true })
.random(3);
console.log('Winners:', winners);
Edge Cases:
// Empty collection
new Collection([]).random(5); // []
// Length greater than collection
new Collection([1, 2, 3]).random(10); // [1, 2, 3] (all items)
// Length of 0
items.random(0); // []
Immutability Note:
const original = new Collection([1, 2, 3, 4, 5]);
const randomItems = original.random(3);
console.log(original.length); // 5 (unchanged)
console.log(randomItems.length); // 3
Difference from shuffle():
// random() - immutable, returns array
const randomItems = items.random(3);
console.log(items); // Unchanged
// shuffle() - mutable, returns collection
items.shuffle();
console.log(items); // Reordered in place
shuffle()¶
shuffle(): this¶
Randomly reorders elements in the collection. This method mutates the collection.
Returns: this - The shuffled collection (for chaining)
Example - Basic shuffle:
const deck = new Collection([
'♠A', '♠2', '♠3', '♠4', '♠5',
'♥A', '♥2', '♥3', '♥4', '♥5'
]);
deck.shuffle();
// deck is now randomly ordered, e.g., ['♥3', '♠A', '♠5', '♥2', ...]
Example - Shuffle and deal:
const cards = new Collection([...52 cards...]);
cards.shuffle();
const player1 = cards.slice(0, 5);
const player2 = cards.slice(5, 10);
const player3 = cards.slice(10, 15);
Example - Random quiz questions:
const questions = new Collection([...quiz questions...]);
questions
.shuffle()
.slice(0, 10)
.each((question, index) => {
console.log(`Q${index + 1}: ${question.text}`);
});
Mutability Note:
const original = new Collection([1, 2, 3, 4, 5]);
original.shuffle();
console.log(original);
// [3, 1, 5, 2, 4] - Reordered in place
To shuffle without mutation:
const shuffled = original.random(); // Use random() instead
console.log(original); // [1, 2, 3, 4, 5] - Unchanged
Chaining:
const result = items
.filter({ available: true })
.shuffle()
.slice(0, 5);
// Get 5 random available items
dump()¶
dump(): this¶
Prints the collection to console and continues execution. Useful for debugging chains.
Returns: this - The collection (for chaining)
Example - Debug in chain:
const result = users
.filter({ active: true })
.dump() // Prints active users
.sort('name', 'asc')
.dump() // Prints sorted active users
.paginate(1, 20);
Example - Inspect transformation:
const processed = orders
.filter({ status: 'completed' })
.dump() // See what's being processed
.map(order => ({
id: order.id,
total: order.items.reduce((sum, item) => sum + item.price, 0)
}))
.dump(); // See final result
Example - Checkpoint debugging:
const data = new Collection(rawData)
.dump() // Checkpoint 1: raw data
.filter({ valid: true })
.dump() // Checkpoint 2: after filter
.unique('email')
.dump() // Checkpoint 3: after unique
.sort('created_at', 'desc');
Output format:
users.dump();
// Logs to console:
// Collection(3) [
// { id: 1, name: 'Alice' },
// { id: 2, name: 'Bob' },
// { id: 3, name: 'Charlie' }
// ]
dd()¶
dd(): never¶
"Dump and Die" - prints collection to console and exits the process (Node.js only). Useful for debugging.
Returns: Never returns (exits process)
Example - Debug and stop:
users
.filter({ role: 'admin' })
.dd(); // Prints admins and exits
// Code after this never executes
console.log('This will not run');
Example - Inspect at specific point:
const result = orders
.filter({ status: 'pending' })
.where('total', '>=', 1000);
if (result.length > 100) {
result.dd(); // Investigate why so many large pending orders
}
Note: Only works in Node.js:
// In Node.js
users.dd(); // Prints and calls process.exit(1)
// In browser
users.dd(); // Only prints (no process.exit)
Difference from dump():
// dump() - continues execution
users.dump().sort('name'); // Prints, then sorts
// dd() - stops execution
users.dd().sort('name'); // Prints and exits, sort never runs
stringify()¶
stringify(replacer?: (key: string, value: any) => any, space?: string | number): string¶
Converts collection to JSON string. Wrapper around JSON.stringify with collection context.
Parameters:
| Parameter | Type | Description |
|---|---|---|
replacer | (key: string, value: any) => any | Optional function to transform values |
space | string \| number | Optional spacing for pretty-printing |
Returns: string - JSON string representation
Example - Basic stringify:
const users = new Collection([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]);
const json = users.stringify();
// '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]'
Example - Pretty print:
const json = users.stringify(null, 2);
// [
// {
// "id": 1,
// "name": "Alice"
// },
// {
// "id": 2,
// "name": "Bob"
// }
// ]
Example - Custom replacer:
const json = users.stringify((key, value) => {
if (key === 'password') return undefined; // Exclude passwords
if (typeof value === 'string') return value.toUpperCase();
return value;
});
Example - Save to file:
import { writeFileSync } from 'fs';
const data = users
.filter({ active: true })
.stringify(null, 2);
writeFileSync('users.json', data);
Example - API response:
app.get('/api/users', (req, res) => {
const users = new Collection(await db.users.findAll());
res.setHeader('Content-Type', 'application/json');
res.send(users.stringify());
});
Example - Filtering sensitive data:
const safeJson = users.stringify((key, value) => {
const sensitive = ['password', 'ssn', 'credit_card'];
return sensitive.includes(key) ? '[REDACTED]' : value;
});
Edge Cases:
// Empty collection
new Collection([]).stringify(); // '[]'
// With Date objects
const events = new Collection([
{ name: 'Event', date: new Date() }
]);
events.stringify(null, 2);
// Date is converted to ISO string
Method Chaining¶
Utility methods integrate seamlessly into method chains:
const result = users
.filter({ verified: true })
.update({ status: 'active' }) // Update verified users
.dump() // Debug: see updated users
.shuffle() // Randomize order
.slice(0, 10); // Take first 10
// Delete inactive, log action
const deleted = users.delete({ active: false });
console.log(`Removed ${deleted} inactive users`);
// Process with early exit
users.each(user => {
processUser(user);
if (shouldStop()) return false;
});
Mutability Reference¶
Mutating Methods (modify original): - update() - Modifies matching elements in place - delete() - Removes matching elements from collection - shuffle() - Reorders elements randomly in place
Immutable Methods (do not modify): - each() - Only iterates, doesn't modify - random() - Returns array, original unchanged - dump() - Only logs, doesn't modify - dd() - Only logs, doesn't modify - stringify() - Returns string, doesn't modify
Safe Mutation Pattern:
// Clone first to avoid mutating original
const processed = users
.collect() // Clone
.update({ verified: true }) // Safe to mutate clone
.delete({ spam: true }) // Safe to mutate clone
.shuffle(); // Safe to mutate clone
// Original unchanged
console.log(users); // Unmodified
Performance Considerations¶
update() and delete() optimization:
// ❌ Bad: Multiple passes
users.update({ type: 'A' }, { status: 'active' });
users.update({ type: 'B' }, { status: 'pending' });
// ✅ Good: Single pass with complex query
users.update({ type: { $in: ['A', 'B'] } }, data => ({
status: data.type === 'A' ? 'active' : 'pending'
}));
each() vs forEach():
// each() allows early exit (more efficient for large collections)
users.each(user => {
if (found) return false; // Stop early
if (user.id === targetId) found = user;
});
// forEach() always iterates all elements
users.forEach(user => {
if (found) return; // Still continues iteration
if (user.id === targetId) found = user;
});
See Also¶
- Transformation Methods - Data transformation
- Filtering Methods - Query and filter data
- Aggregation Methods - Calculate statistics
- Best Practices - Usage patterns and optimization