Как фильтровать сложные данные с использованием JavaScript / TypeScript | Блог Work Solutions
Как фильтровать сложные данные с использованием JavaScript / TypeScript
ГлавнаяБлогРазработчикамКак фильтровать сложные данные с использованием JavaScript / TypeScript
Разработчикам11 марта 2020

Как фильтровать сложные данные с использованием JavaScript / TypeScript

Фотография автора
Дмитрий ПереверзаTech Lead

Часто ли вам приходилось писать обработчики фильтрации для ваших данных? Это могут быть массивы для отрисовки таблиц, карточек, списков — чего угодно.

Когда фильтрация статическая, то тут все просто. Стандартных функций map, filter и reduce вполне достаточно. Но что делать, если данные имеют сложную структуру или вложенность, да еще и правил для фильтра может быть достаточно много. Правила могут повторяться, данные изменяться, и чем больше контролов фильтра будет появляться, тем сложнее и неустойчивее будет код обработчика.

Как же решить проблему возрастающей сложности?

Я сам столкнулся с данной проблемой, разрабатывая приложение, которое работает с огромным количеством данных. Постепенно добавлялись все новые и новые фильтры.

Поначалу все шло хорошо, отдельные обработчики фильтров выполняли свои задачи отлично. Со временем стали появляться страницы с незначительными изменениями в уже готовых фильтрах. Код дублировать не хотелось, так что пришлось выделять особенные варианты фильтра и его обработчика. Типовая страница собиралась за час, но вот обработчики для фильтров писались в два раза дольше. Нужно было что-то делать.

В свободное время я пробовал найти библиотеки, которые могли бы помочь решить эту проблему.Самые значимые библиотеки, которые удалось найти:

  1. ng-table — отрисовывает таблицы и предоставляет возможность простой фильтрации и сортировки. Фильтрации у нас были намного сложнее.
  2. List.js — как ng-table, только намного меньше функционала.
  3. filter.js — близко к тому, что было нужно, но не хватало гибкости.
  4. Isotope — привязывается к DOM элементам. У нас же просто данные.

Нужно было разработать собственное решение, удовлетворяющее следующим требованиям:

  1. Декларативное описание работы фильтра.
  2. Переиспользуемые правила.
  3. Возможность написания своих правил фильтрации.
  4. Композиция правил как в обычных условиях, с помощью and и or операторов.
  5. Фильтрация вложенных элементов и групп. Вложенность не фиксированная.
  6. Возможность задать стратегию фильтрации (к примеру, мы хотим, чтобы, если группа совпала с фильтром, но не совпал ни один из её элементов, все равно вывелась группа со всеми элементами)

В итоге мы имеем библиотеку awesome-data-filter.

Данная библиотека, используя декларативный подход, позволяет составлять сложные правила обработки ваших данных.

Установка

Сначала поставим библиотеку и опробуем ее в действии.

Изображение статьи

Начнем с простого примера. Предположим, у нас есть следующий массив пользователей:

Изображение статьи

И объект со значениями фильтра:

Изображение статьи

Допустим, нужно найти пересечение этих правил.

Используемые правила:

  • matchText — поиск подстроки в целевом поле;
  • equalProp — полное совпадение значений параметров;
    • betweenDates — проверяет вхождение определенной даты в диапазон;
    • equalOneOf — хотя бы один из переданных элементов должен соответствовать переданному правилу;
    • someInArray — хотя бы один из вложенных элементов объекта должен соответствовать переданному правилу;
    • isEmptyArray — проверка на пустой массив;
    • lessThen — значение меньше, чем;
    • moreThen — значение больше, чем;
    • not — функция отрицания возвращаемого функцией значения.
Изображение статьи

В наших примерах мы будем использовать только matchText и equalProp.

Для получения динамических значений:

  • filterField — получение свойства фильтра;
  • elementField — получение свойства текущего элемента списка.

Полученная функция 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 можно решить проблему со сложностью обработчиков фильтров и улучшить читабельность кода. Теперь можно визуально сравнить графики сложности обоих подходов.

Если на вашем проекте не используется много фильтров и проект сам по себе небольшой, то вам не нужна эта библиотека. Остальным же можно пробовать внедрять ее постепенно.

1.6к
267

Другие статьи

Ко всем статьям
Фоновое изображение: четверть круга закрыват часть круга

Интересные статьи и кейсы
от Work Solutions

Нажимая кнопку «Подписаться», я даю согласие на обработку персональных данных

Спасибо за подписку!

Фоновое изображение: верхний полукруг