Where?

Overview

This where() function aims to provide sql-like filtering for arrays of objects. It allows you to filter collections using simple or complex criteria, including nested properties.

Could you usually use Array.filter() instead? Yes, almost always. But I think this is a bit prettier.

Basic Usage

const users = [
    { name: 'Tziporah', age: 30 },
    { name: 'Bruce', age: 25 },
    { name: 'Ruth', age: 30 }
];

// Find everyone who is 30 years old
const thirtyYearOlds = where(users, { age: 30 });
// Result: [{ name: 'Tziporah', age: 30 }, { name: 'Ruth', age: 30 }]

More Advanced Features

1. Nested Object Properties

const users = [
    { 
        name: 'Bruce',
        preferences: { 
            theme: 'dark',
            notifications: { email: true }
        }
    }
];

// Find people with the dark theme enabled
const darkThemeUsers = where(users, {
    preferences: { theme: 'dark' }
});

2. Dot Notation

// Same query using dot notation
const darkThemeUsers = where(users, {
    'preferences.theme': 'dark'
});

3. Multiple Criteria

// Find folks who are 30 AND prefer dark theme
const result = where(users, {
    age: 30,
    'preferences.theme': 'dark'
});

4. Array Matching

const users = [
    { 
        name: 'Jeremiah',
        hobbies: ['reading', 'music']
    }
];

// Find people with exact hobby matches
const readers = where(users, {
    hobbies: ['reading', 'music']
});

The Key Features

Limitations & Edge Cases

1. Partial Array Matches

const users = [
    { 
        name: 'Bruce',
        hobbies: ['reading', 'music', 'hiking']
    }
];

// This won't match Bruce's hobbies
const result = where(users, {
    hobbies: ['reading', 'music']
}); // Returns []

// Arrays must match exactly in length and content

2. OR Operations

// This won't work for finding users aged 25 OR 30
const result = where(users, {
    age: [25, 30]  // This looks for an exact array match
});

// Consider using Array.filter() directly for OR operations:
const result = users.filter(user => 
    user.age === 25 || user.age === 30
);

3. Complex Comparisons

// These operations are NOT supported:
where(users, {
    age: (age) => age > 30,     // Function predicates
    salary: { $gt: 50000 },     // MongoDB-style operators 🤮
    'name.length': 4            // Property operations
});

4. Regular Expressions

// RegExp matching also isn't implemented
where(users, {
    email: /.*@gmail\.com$/
});

// Use Array.filter() instead:
const gmailUsers = users.filter(user => 
    /.*@gmail\.com$/.test(user.email)
);

5. When Not to Use

6. Performance Considerations

// Avoid deeply nesting with large arrays
const deeplyNested = where(largeArray, {
    'level1.level2.level3.level4.property': value
});

// Each level of nesting increases complexity

// Use direct access whenever possible:
const result = largeArray.filter(item => 
    item.level1?.level2?.level3?.level4?.property === value
);

Test Results