BACK
Use casesPer-entity grouping — a separate stream per id
Use cases · 61

Per-entity grouping — a separate stream per id

Pattern

A WebSocket emits events for different entities interleaved: update id=a, update id=b, update id=a. Each entity should update ITS OWN state independently. Logically N streams, physically one.

The problem it solves

One shared reducer with nested maps (state[id].counter += delta) quickly gets complex. Mutations kill the entities' independence. Testing "this event sequence leads to state X for id=a" is awkward.

Operators and why they matter

  • groupBy(event => event.id) — splits one stream into N streams by the id key.
  • mergeMap(group$ => ...) — subscribe to each group.
  • scan inside the group — an independent reducer for that specific entity.
  • map — build the per-entity update.

Gotchas

  • groupBy with unbounded ids — a memory leak; groups are kept forever. Use a durationSelector for cleanup.
  • scan mutating a shared object instead of immutable updates — breaks the groups' independence.
  • If the global order of changes across entities matters, mergeMap is too loose. You'll need concatMap or extra synchronization.

What you get

Each entity gets its own independent state stream. The logic is clean, testable, and free of nested mutations.

script.ts // TypeScript
CONSOLE · Console output
Hit Run to see the result...