0

I'm trying to implement a sorting function that takes in an array of objects and sorts them by an attribute or a nested attribute. I've looked at a ton of questions on here with good answers to this problem, but so far as I have seen, none of them account for when a nested attribute is missing.

For example, if I sort by some_attribute and some_attribute = undefined for one of my array elements, the element in question is bumped to the end/beginning of the array, as I would expect. If I sort by some_attribute.something_else, the functions I've seen don't respond well when some_attribute.something_else = undefined.

Here is a sample of my data structure I'm trying to sort:

results = [
    {
        id: 233,
        post: "Test 944 AM http://frmply.co/1mA9G3L",
        twitter_favorite_count: 0,
        twitter_retweet_count: 2,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 3
        },
        twitter_last_updated: "2015-12-28T21:11:27.425Z",
        facebook_like_count: null,
        facebook_share_count: 1,
        facebook_comment_count: null,
        facebook_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 1
        },
        facebook_last_updated: "2015-12-28T21:11:29.232Z",
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        linkedin_last_updated: "2015-12-28T21:11:29.905Z"
    },
    {
        id: 232,
        post: "Test 944 AM http://frmply.co/1mA9G3L",
        twitter_favorite_count: null,
        twitter_retweet_count: null,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 5
        },
        twitter_last_updated: null,
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: { },
        facebook_last_updated: null,
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: { },
        linkedin_last_updated: null
    },
    {
        id: 234,
        post: "localhost test 1106am http://frmply.co/1RAYalE",
        twitter_favorite_count: 0,
        twitter_retweet_count: 0,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 2
        },
        twitter_last_updated: "2016-01-06T18:40:21.388Z",
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        facebook_last_updated: "2015-12-29T16:07:39.042Z",
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        linkedin_last_updated: "2015-12-29T16:07:39.489Z"
    },
    {
        id: 231,
        post: "test",
        twitter_favorite_count: null,
        twitter_retweet_count: null,
        twitter_link_click_count: { },
        twitter_last_updated: null,
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: { },
        facebook_last_updated: null,
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: { },
        linkedin_last_updated: null
    }
]

Now if I run the code below I get [2, 3, 5, undefined] as a result when I would expect [undefined, 2, 3, 5].

results.sortBy('twitter_link_click_count.total').map(function(x){return x.twitter_link_click_count.total})

In the snippet above, sortBy is a function from this post, however I've also tried using Underscore's _.sortBy function with identical results.

Working Code

Here is the solution I came up with based off Oleg's answer:

var sortKey = attribute.split('.');
var sortBy = function(results, sortKey) {
    return _.sortBy(results, function(item) {
        if(sortKey.length === 1) {
            return item[sortKey[0]] || 0;
        } else {
            return item[sortKey[0]][sortKey[1]] || 0;
        };
    });
};

The key difference here is that it generates a sortKey array, which can be used an an if/else statement or iterated over. I used an if/else since my sortKey is only ever 1 or 2 layers deep inside my object. I also handled cases where my attribute is null by returning 0 instead of true. Hope this helps someone else.

2 Answers 2

1

Please try the following script (used Underscore there):

results = [
    {
        id: 233,
        post: "Test 944 AM http://frmply.co/1mA9G3L",
        twitter_favorite_count: 0,
        twitter_retweet_count: 2,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 3
        },
        twitter_last_updated: "2015-12-28T21:11:27.425Z",
        facebook_like_count: null,
        facebook_share_count: 1,
        facebook_comment_count: null,
        facebook_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 1
        },
        facebook_last_updated: "2015-12-28T21:11:29.232Z",
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        linkedin_last_updated: "2015-12-28T21:11:29.905Z"
    },
    {
        id: 232,
        post: "Test 944 AM http://frmply.co/1mA9G3L",
        twitter_favorite_count: null,
        twitter_retweet_count: null,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 5
        },
        twitter_last_updated: null,
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: { },
        facebook_last_updated: null,
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: { },
        linkedin_last_updated: null
    },
    {
        id: 234,
        post: "localhost test 1106am http://frmply.co/1RAYalE",
        twitter_favorite_count: 0,
        twitter_retweet_count: 0,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 2
        },
        twitter_last_updated: "2016-01-06T18:40:21.388Z",
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        facebook_last_updated: "2015-12-29T16:07:39.042Z",
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        linkedin_last_updated: "2015-12-29T16:07:39.489Z"
    },
    {
        id: 231,
        post: "test",
        twitter_favorite_count: null,
        twitter_retweet_count: null,
        twitter_link_click_count: { },
        twitter_last_updated: null,
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: { },
        facebook_last_updated: null,
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: { },
        linkedin_last_updated: null
    }
];

document.getElementById('output').innerHTML = JSON.stringify(_.sortBy(results, function(item) {
  return item.twitter_link_click_count.total || true;  
}).map(function(x){return x.twitter_link_click_count.total}));
<script src="http://underscorejs.org/underscore-min.js"></script>
<pre id="output"></pre>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! It upvoted your answer because even though it didn't quite solve my problem, it gave me a hint (returning the item attribute or true / 0) that allowed me to solve it. I've updated my question above with the working code.
0

Solution using plain JS filter & map

results = results.filter(function (a) {
    return !!((a.twitter_link_click_count || {}).total)
}).sort(function(a, b){
    return (a.twitter_link_click_count || {}).total > (b.twitter_link_click_count || {}).total
})

1 Comment

That works if I only care about the order of x.twitter_link_click_count.total, however that's just an attribute I want to sort my objects by.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.