Dataviewjs sort multiple columns

Things I have tried

for (let group of dv.pages("[[#]]").groupBy(p => p.type)) {
    dv.header(2, group.key);
    dv.table(["Title", "Rating"], // header
        group.rows
            .sort(k => k.rating, 'desc', k.file.link, 'asc')
            .map(k => [k.file.link, k.rating]))
}

What I’m trying to do

I want to group by the type and then sort within each group, first by rating and then by file.link. The issue is doing the double sort. Everything else works. If I remove the ", k.file.link, ‘asc’ " then it works (except the links aren’t sorted).

I see at least two possible ways forward:

  1. Add multiple .sort() statements, and play around with the order of those
  2. Extend the returned value by the .sort() into some combination of the rating and the link

So what happens if you do something like:

  group.rows
    .sort(k => k.rating, 'desc')
    .sort(k => k.file.link, 'asc')
    .map( ... )

or something like:

  group.rows
    .sort(k => k.rating + k.file.name, 'asc')
    .map( ... )

Or maybe that should be more like `${1000 - k.rating}${k.file.name} in order to get the reversed rating sorting. This as can be seen, is a cludgy way to turn both fields into a single string, and can be troublesome to handle, but I’ve resorted to this in my early days programming a few decades ago.

Hope this helps, and please return with more information as to how you either solved it, or where you’re currently stuck in your process of achieving your goal here.

I don’t know how to sort by multiple criteria in js, but I think this doesn’t work because the second sort ignore the first one.

Another thing. Links aren’t strings… so, when we use a kind of “sort by link” I think it will sort by the link path. If files aren’t all in the same folder the results will be a mess. :slight_smile:
In this cases, choose always file.name.

I’m not sure how this Obsidian’s sort() works, and it can be a bit of gamble. However, some(/most?) implementations of sort preserve the previous order of the list if the new sort order is identical.

This (has been or) can be used to our advantage, as you then first sort the list according to your least important sort category, and then keep sorting the list according to higher priority sort category. In the end, it actually turns out to be sorted with respect to all your sort categories, but you’ve only done one at a time.

Caveat, I don’t know if Obsidian’s sort methods adheres to this principle or not, so it needs to be tested out. It could very well, change the entire order in each go, rendering the previous sort obsolete.

Regarding your note on k.file.link vs k.file.name, you’ll see that in the second part, I did indeed resort to the string version, aka k.file.name, just avoid that link issue.

1 Like

Oh, I see. I need to test that. thanks.
By the way, if all sorts in same “direction”: DataArray: sorting by multiple keys · blacksmithgu/obsidian-dataview · Discussion #364 · GitHub

Yes, I tried this and it works as you suggest. If the sort maintained order for equal items, it would work. But, apparently it does not

@mnvwvnm was on the right track. The big issue was that I was sorting by links (k.file.link) instead of names (k.file.name). I believe link sorting was using the full path which isn’t what I wanted. Sorting by k.file.name fixed that.

It appears the sort is preserving order for equal items (meaning that if when doing a sort, if two items are equal, then they are left in the same order as they were found). This means that what I need is:

group.rows
    .sort(k=>k.file.name, 'asc')
    .sort(k => k.rating, 'desc')
    .map( ... )

The first sort sorts all of the items alphabetically. The second sort sorts them by ratings with the highest rating first. If there are multiple items with the same rating, then the old name order is preserved so within each rating, the items are sorted by name.

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.