lodash orderby with null and real values not ordering correctly

18,458

Solution 1

The code I needed looks like this...

_.orderBy(this.myArray, [( o ) => { return o.myProperty || ''}], ['desc']); 

Solution 2

The _.orderBy() function's iteratees can use a method instead of a string. Check the value, and if it's null return an empty string.

const myArray = [{ propertyName: 'cats' }, { propertyName: null }, { propertyName: 'dogs' }, { propertyName: 'rats' }, { propertyName: null }];

const result = _.orderBy(myArray, ({ propertyName }) => propertyName || '', ['desc']);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

The check can be simple (like the one I've used), which converts all falsy values to an empty string:

propertyName || ''

If you need a stricter check, you can use the ternary operator, and handle just null values:

propertyName === null ? '' : propertyName

Edit: Example with multiple ordering:

const result = _.orderBy(myArray, (item) => [get(item, 'propertyName', 0), get(item, 'propertyName2')], ['desc', 'asc']);

This will order by propertyName then propertyName2.

If propertyName is undefined/null then its default order will be set to 0. (and therefore will be displayed at last because of desc ordering on the propertyName field). In such case, propertyName2 will therefore determine the ordering.

Solution 3

Just for future reference to others you can do this to sort ascending with falsey values at the end.

items =>
  orderBy(
    items,
    [
      i => !!i.attributeToCheck,
      i => {
        return i.attributeToCheck ? i.attributeToCheck.toLowerCase() : ''
      }
    ],
    ['desc', 'asc']
  )

Solution 4

This will put bad values at the bottom, and it differentiates between numbers and strings.

const items = [] // some list

const goodValues = isAscending => ({ value }) => {
    if (typeof value !== 'string' && isNaN(value)) {
        return isAscending ? Infinity : -Infinity
    }

    return value || ''
}

const sortedItems = orderBy(
    items,
    [goodValues(isAscending), 'value'],
    [isAscending ? 'asc' : 'desc']
)

Solution 5

This worked for me

orders = [{id : "1", name : "test"}, {id : "1"}];
sortBy = ["id", "name"];
orderby(
            orders,
            sortBy.map(s => {
                return (r: any) => {
                    return r[s] ? r[s] : "";
                };
            })),
        );
Share:
18,458
Ben Cameron
Author by

Ben Cameron

I'm a .net, JavaScript, and Angular developer based in London UK. I love to dev.

Updated on June 11, 2022

Comments

  • Ben Cameron
    Ben Cameron almost 2 years

    I have an Angular 2 typescript application that is using lodash for various things.

    I have an array of objects that I am ordering using a property in the object...

    _.orderBy(this.myArray, ['propertyName'], ['desc']);
    

    This works well however my problem is that sometimes 'propertyName' can have a null value. These are ordered as the first item in a descending list, the highest real values then follow.

    I want to make these null values appear last in the descending ordering.

    I understand why the nulls come first.

    Does anyone know how to approach this?

  • Ben Cameron
    Ben Cameron over 7 years
    Very close, thank you. I've posted the full solution below.
  • Ori Drori
    Ori Drori over 7 years
    Why do you need all the extra stuff [( o ) => { return o.myProperty || ''}]? My solution works out of the box. See the snippet. Just replace propertyName with the name of the property.
  • Ben Cameron
    Ben Cameron over 7 years
    It didn't seem to work for me the way you had it but it did the way I had it. Maybe its a lodash thing or something. In any case the problem is solved now. Thanks for your help.
  • Ori Drori
    Ori Drori over 7 years
    Weird. Maybe typescript doesn't like it.
  • stallingOne
    stallingOne almost 6 years
    this still sorts nulls abode in asc order, is there a ways have null always at end ?
  • stallingOne
    stallingOne almost 6 years
    this still sorts nulls first in 'asc' order, is there a ways have null always at end ?
  • Ori Drori
    Ori Drori almost 6 years
    @stallingOne - it's not an elegant solution, but you can replace it with some later characters, such as a sequence of tildes - ~~~~~~~~~~~~. A case like this is better handled with the JS sort.
  • alextouzel
    alextouzel almost 5 years
    @stallingOne i know this is old but for anyone trying to achieve this you can try _.orderBy(this.myArray, o => o || undefined)
  • Vadorequest
    Vadorequest over 4 years
    Should be the accepted answer. @BenCameron would you mind accept it?