Sort by one value first, then by another

I want Meteor to sort documents that have a certain value (1) first, and then it should sort them all by date.

Collection.find(selector, {
          sort: {
              starred: -1,
              createdAt: -1
          }
        });

Basically, I want the documents that has starred set to 1 to show up first, no matter when they were made. Then it should sort the rest (starred 0) by date, below the starred ones. How can this be done?

You’ll probably require a js sort. You can specify a js sort in minimongo by using a js function as your sort specifier.

Do you have any examples?

The way to write the sort specifier for minimongo using javascript is in the docs (see sort specifier). As for the algorithm, your compare function would look something like

function(a,b) {
   if (a.starred) return (b.starred)? 0:-1;
   if (b.starred) return 1;
   return a.createdAt - b.createdAt;
}

I thought it was supported by minimongo. It wasn’t?

use lodash to replace meteor underscore

https://lodash.com/docs/4.17.5#sortBy

Thanks for the answers everyone. I solved it using a sort specifier as suggested by @dpatte

I’ll admit I’m as confused by this as @minhna.

As you’ve described the problem, the query you initially provided will do what you want (all starred === 1 ahead of all starred === 0). Within each starred grouping, documents will be in “most recent first” order.

MyCollection.find().fetch();
(7) 0: {starred: 0, createdAt: Mon Mar 19 2018 13:31:23 GMT+0000 (GMT Standard Time), _id: "PzZdykHWGL4tRF7kK"}
    1: {starred: 0, createdAt: Mon Mar 19 2018 13:31:29 GMT+0000 (GMT Standard Time), _id: "ET4XtzdEj7h7WjxA5"}
    2: {starred: 1, createdAt: Mon Mar 19 2018 13:31:37 GMT+0000 (GMT Standard Time), _id: "n8zK9xGrXY2QAPM9T"}
    3: {starred: 1, createdAt: Mon Mar 19 2018 13:31:41 GMT+0000 (GMT Standard Time), _id: "e8BbTp9GFx6zkTNFT"}
    4: {starred: 0, createdAt: Mon Mar 19 2018 13:36:51 GMT+0000 (GMT Standard Time), _id: "uoKzw3PzKB84kLQFf"}
    5: {starred: 0, createdAt: Mon Mar 19 2018 13:36:52 GMT+0000 (GMT Standard Time), _id: "jcYPoz6XSC6XfRmbu"}
    6: {starred: 1, createdAt: Mon Mar 19 2018 13:38:00 GMT+0000 (GMT Standard Time), _id: "sx9PSE4vXaNyDz3Rv"}

MyCollection.find({},{ sort:{ starred:-1, createdAt:-1 } }).fetch();
(7) 0: {starred: 1, createdAt: Mon Mar 19 2018 13:38:00 GMT+0000 (GMT Standard Time), _id: "sx9PSE4vXaNyDz3Rv"}
    1: {starred: 1, createdAt: Mon Mar 19 2018 13:31:41 GMT+0000 (GMT Standard Time), _id: "e8BbTp9GFx6zkTNFT"}
    2: {starred: 1, createdAt: Mon Mar 19 2018 13:31:37 GMT+0000 (GMT Standard Time), _id: "n8zK9xGrXY2QAPM9T"}
    3: {starred: 0, createdAt: Mon Mar 19 2018 13:36:52 GMT+0000 (GMT Standard Time), _id: "jcYPoz6XSC6XfRmbu"}
    4: {starred: 0, createdAt: Mon Mar 19 2018 13:36:51 GMT+0000 (GMT Standard Time), _id: "uoKzw3PzKB84kLQFf"}
    5: {starred: 0, createdAt: Mon Mar 19 2018 13:31:29 GMT+0000 (GMT Standard Time), _id: "ET4XtzdEj7h7WjxA5"}
    6: {starred: 0, createdAt: Mon Mar 19 2018 13:31:23 GMT+0000 (GMT Standard Time), _id: "PzZdykHWGL4tRF7kK"}
2 Likes

@robfallows That is very weird because it didn’t work out for me.

I ended up doing it like this

(server)

Meteor.publish('topics', function(limit) {
        check(limit, Number);

      	return Topics.find({}, {
          limit: limit,
          sort: {starred:-1}
        });
    });

(client)

Template.indexTopics.helpers({
        topics: function () {
            var cursor = Topics.find({});
            cursor.sorter = {
              getComparator: function() {
                return function(a, b) {
                    if (a.starred) return (b.starred) ? 0 : -1;
                    if (b.starred) return 1;
                    return b.createdAt - a.createdAt;
                }
              }
            };
            return cursor;
        }
    });

As a side note, I didn’t mention it because I didn’t think it was relevant, but I’m using this for an infinite scrolling system. Nonetheless, it is working now.