Use cases/Per-entity grouping — отдельный поток на id
Use cases · 61 実
Per-entity grouping — отдельный поток на id
Паттерн
WebSocket эмитит события по разным сущностям вперемешку: update id=a, update id=b, update id=a. Каждая сущность должна обновлять СВОЁ состояние независимо. Логически это N потоков, физически — один.
Какую проблему решаем
Один общий reducer с nested maps (state[id].counter += delta) быстро усложняется. Мутации убивают independence сущностей. Тестировать «вот эта последовательность событий приводит к состоянию X для id=a» неудобно.
Операторы и зачем они нужны
groupBy(event => event.id) — разбивает один поток на N streams по ключу id.
mergeMap(group$ => ...) — подписываемся на каждую группу.
scan внутри группы — независимый reducer для конкретной сущности.
map — формирует per-entity update.
Подводные камни
groupBy при unbounded ids — утечка памяти, группы хранятся вечно. Используйте durationSelector для cleanup.
scan с мутацией общего объекта вместо immutable updates — ломает независимость групп.
Если важен глобальный порядок изменений между сущностями — mergeMap слишком свободный. Понадобится concatMap или дополнительная синхронизация.
Что в итоге получаем
Каждая сущность получает собственный независимый поток состояния. Логика чистая, тестируемая, без nested mutations.