How to do LiveView stream sorting?

My app lets people connect their Garmin, Apple Watch, etc, to track activities, join virtual races, and create adventure activity plans. I have a leaderboard which is backed by a LiveView, in turn subscribed to a pub sub channel.

I’m using |> stream to add leaderboard data into my LiveView. When a new activity comes in from the provider, I broadcast a message with the new aggregate data for that runner.

And like magic, my leaderboard LiveView updates. There’s just one problem. Sorting!

If a runner overtakes another, the leaderboard is out of order. One simple fix is just to recompute the whole thing. But that feels inefficient — I can’t rely on stream_insert anymore.

Yet sorting at the template level also seems like it violates the design intention of streams.

Any thoughts on the “right” way to resolve this? Thank you!

The stream_insert/4 function accepts an :at argument to specify where to insert an item. I’m not sure if it works for updates though, and the docs seem to suggest it does not although it’s a bit vague.

However, you should be able to call stream_delete/3 and then stream_insert/4 in that case to forcibly relocate the item in the DOM.

A quick thought is to continue using streams to add/update new data, but use a JS hook client-side to resort after update. You could do this if you added data-sort-value={@your_sorting_value} to the leader board items, and after the resort, trim excess elements.

The advantage of this is that you don’t need to track which position it belongs in server-side.