Часто ли вам приходилось писать обработчики фильтрации для ваших данных? Это могут быть массивы для отрисовки таблиц, карточек, списков — чего угодно. Когда фильтрация статическая, то тут все просто. Стандартных функций map, filter и reduce вполне достаточно. Но что делать, если данные имеют сложную структуру или вложенность, да еще и правил для фильтра может быть достаточно много. Правила могут повторяться, данные изменяться, и чем больше контролов фильтра будет появляться, тем сложнее и неустойчивее будет код обработчика. Как же решить проблему возрастающей сложности? Я сам столкнулся с данной проблемой, разрабатывая приложение, которое работает с огромным количеством данных. Постепенно добавлялись все новые и новые фильтры. Поначалу все шло хорошо, отдельные обработчики фильтров выполняли свои задачи отлично. Со временем стали появляться страницы с незначительными изменениями в уже готовых фильтрах. Код дублировать не хотелось, так что пришлось выделять особенные варианты фильтра и его обработчика. Типовая страница собиралась за час, но вот обработчики для фильтров писались в два раза дольше. Нужно было что-то делать. В свободное время я пробовал найти библиотеки, которые могли бы помочь решить эту проблему.
Самые значимые библиотеки, которые удалось найти: Нужно было разработать собственное решение, удовлетворяющее следующим требованиям: В итоге мы имеем библиотеку awesome-data-filter. Данная библиотека, используя декларативный подход, позволяет составлять сложные правила обработки ваших данных. Сначала поставим библиотеку и опробуем ее в действии. Начнем с простого примера.
Предположим, у нас есть следующий массив пользователей: И объект со значениями фильтра: Допустим, нужно найти пересечение этих правил. Используемые правила: В наших примерах мы будем использовать только matchText и equalProp. Для получения динамических значений: Полученная функция filter принимает объект со значениями фильтра и фильтруемые данные в формате groups и elements. Так как группы обрабатываются отдельно от элементов, они вынесены в отдельное поле. Внутри групп также могут находиться элементы.  В данном случае, так как у нас плоский список элементов, передаем только elements. Если же заменим and на or, то получим объединение результатов работы 2х правил. Благодаря функциям filterField, elementField мы можем динамически передавать параметры в созданные правила. Так же есть функция constValue для передачи константных значений.
Условия могут вкладываться друг в друга or(..., matchText, [and([..., matchText, ...]), or([..., ...])]) Также фильтр может работать со вложенными элементами и группами. Рассмотрим на примере ниже: В таком случае можно передать в конфиг фильтра информацию об обходе данной структуры объекта в поле traversal:  До этого момента передавался только elementFilter параметр, который отвечает за правила фильтрации элементов. Также есть groupFilter для групп. Группа с названием first group появилась в выборке, и так как фильтр не нашел совпадения по элементам, но нашел совпадение по группе, мы видим отображение всех вложенных элементов списка.
В случае с fifth group совпадение было и по элементам, и по группе, поэтому оставляем только один элемент. Подобные зависимости фильтрации между группами и элементами называются стратегией фильтрации. По умолчанию указана следующая стратегия: Если стандартная стратегия не подходит для вашего случая, можно написать свою и передать ее в поле фильтра filterStrategy. Благодаря использованию библиотеки awesome-data-filter можно решить проблему со сложностью обработчиков фильтров и улучшить читабельность кода. Теперь можно визуально сравнить графики сложности обоих подходов.  Если на вашем проекте не используется много фильтров и проект сам по себе небольшой, то вам не нужна эта библиотека. Остальным же можно пробовать внедрять ее постепенно. Буду рад вашим комментариям, вопросам и советам. Ведущий Frontend-разработчик в компании Just-AI