DEV Community

Pearl Zeng-Yoders
Pearl Zeng-Yoders

Posted on

3 1 1

Eight (Groups of) Lodash Functions I Reach for the Most

Wanted to share some Lodash functions that I reach out to a lot either in our React frontend or Node backend. I find them handy and that they improve code readability.

1. lodash/get

Use case: Get a property or nested property from an object when the object or its properties are potentially undefined. Can also provide a default value if needed.

// Examples: get company and department properties of a person,
// variable `person` has the following type interface:
interface Person {
    firstName: string;
    lastName: string;
    company?: {
        name: string;
        // ...other company props
        department?: {
            name: string;
            // ...other department props
        }
    }
}

// Example 1: Get the name of the person's company, 
// if undefined, give it ‘Company S’;
// Using syntax 1: use string to express props to look up
const companyName = get(person, 'company.name', 'Company S');

// Example 2: Get the name of the person's department, 
// if undefined, give it ‘Department E’;
// Using syntax 2: use array of strings to express props to look up
cont departmentName = get(person, ['company', 'department', 'name'], 'Department E');
Enter fullscreen mode Exit fullscreen mode

Both syntax allow the use of variables if the look up property name is a variable:

// syntax 1:
const somePropOfCompany = get(person, `company[${propName}]`);

// syntax 2: 
const somePropOfCompany = get(person, ['company', propName]);
Enter fullscreen mode Exit fullscreen mode

2. lodash/partition, lodash/difference, & lodash/intersection

Use case: I reach for these functions when needing to handle parts of an array differently.

lodash/partition

// Example: Given an array of items, handle featured items and the rest of the items differently,
// variable `item` has the following type interface:
interface Item {
    name: string;
    isFeatured: boolean;
    category: 'Hobby' | 'Skill' | 'Other';
};

const itemList: Item[] = [
    {
        name: 'my hobby 1',
        isFeatured: false,
        category: 'Hobby',
    },
    {
        name: 'my hobby 2',
        isFeatured: true,
        category: 'Hobby',
    },
    {
        name: 'my skill 1',
        isFeatured: true,
        category: 'Skill',
    },
    {
        name: 'my item 100',
        isFeatured: false,
        category: 'Other',
    }
  // ... more items like the above
];

// Use partition to get a list of featured items and a list of the rest of the items
const [featuredItems, restOfItems] = partition(itemList, { isFeatured: true });

// The second argument can also be a function instead of a property object,
// for example, partition a list of featured hobby items from the rest of the items
const [featuredHobbyItems, restOfItems] = partition(itemList, 
    item => item.isFeatured && item.category === 'Hobby');
Enter fullscreen mode Exit fullscreen mode

lodash/difference

// Example: Given a list of incoming members and a list of members from user input,
// get the members to add
const currentMembers = [
  // ...an array of existing members from the API
]; 
const incomingMembers = [
    // ...an array of new members from the form input
]; 
const membersToAdd = difference(incomingMembers, currentMembers);
Enter fullscreen mode Exit fullscreen mode

lodash/intersection

// Example: given the same member list from the above, get the members to remove
const membersToRemove = intersection(currentMembers, incomingMembers);
Enter fullscreen mode Exit fullscreen mode

3. lodash/keyBy & lodash/groupBy

Use case: Build a lookup – keyBy uses one object property as the key, and groupBy groups array items with the same keys into an array under that key.

lodash/keyBy

// Example: Given a list of people with the following type interface,
// get a lookup of people by id
interface Person {
    id: string;
    firstName: string;
    lastName: string;
    companyName: string;
};

const people: person[] = [
    // ...list of people
];

const peopleLookup = keyBy(people, 'id');

// Resulting interface:
interface PeopleLookup {
    [id: string]: Person;
};
Enter fullscreen mode Exit fullscreen mode

lodash/groupBy

// Example: Given a list of people like the above,
// get a lookup of people by company name
const peopleByCompany = groupBy(people, 'companyName');

// Resulting interface:
interface PeopleByCompany {
    [companyName: string]: Person[];
};
Enter fullscreen mode Exit fullscreen mode

4. lodash/compact & lodash/isEmpty

Use case: Make sure intended operations don’t happen on falsey items.

lodash/compact

// Example: Given a list of people with the following interface,
// get a list of profile photo urls
interface Person {
    firstName: string;
    lastName: string;
    profilePictureUrl?: string;
};

const people: Person[] = [
    // ...list of people
];

const profilePictureUrls = compact(people.map(p => p.profilePictureUrl));
// Using compact here will get rid of any undefined, null, or empty values
Enter fullscreen mode Exit fullscreen mode

lodash/isEmpty

// Example 1: Given the people list like the above,
// call the API to upload the photos if profilePictureUrls is not empty
if (!isEmpty(profilePictureUrls)) {
    // call the API
}; // Can also be accomplished by checking array length

// Example 2: Given an object of props to update for a person,
// call the person update endpoint if there are items to update
interface PersonUpdate {
    email?: string;
  phoneNumber?: string;
    company?: {
        name?: string;
        department?: string;
    };
  // ...many more properties
}

if (!isEmpty(PersonUpdate)) {
    // call the person update endpoint
}
Enter fullscreen mode Exit fullscreen mode

5. lodash/pick, lodash/omit, lodash/uniq, & lodash/isEqual

Use case: Grab intended properties to send to the API or for display on the UI.

// Examples: Given updatePersonRequest,
const validPersonProps = ['firstName', 'lastName', 'email', 'number'];
// Use pick to grab valid props to send to the updatePerson API endpoint
await updatePerson(pick(updatePersonRequest, validPersonProps));

const propsToSendSeparately = ['profilePhotoUrl', 'coverPhotoUrl'];
// Use omit to omit properties that are handled via a different endpoint
await updatePerson(omit(updatePersonRequest, propsToSendSeparately));

// Use isEqual to decide whether to call the updateEndpoint,
// it performs a deep comparison
if (!isEqual(currentPersonValue, editedPersonValue)) {
    // call the update endpoint
};

// Let's say for every companyName, we need to create a company profile page
const personList = [
    {
        firstName: 'John'
        lastName: 'Doe',
        companyName: 'Company A'
  },
    {
        firstName: 'Sara'
        lastName: 'Smith',
        companyName: 'Company A'
  },
    {
        firstName: 'James'
        lastName: 'Bond',
        companyName: 'Company B'
  },
  // ...more person objects like the above
];
// Use uniq to avoid duplicated company page creation
const namesForCompanyPageCreation = uniq(personList.map(p => p.companyName));
Enter fullscreen mode Exit fullscreen mode

6. lodash/sortBy & lodash/orderBy

Use case: Sort and order array items.

sortBy sorts items in ascending order, and orderBy allows specifying the sort order.

// Examples:
// Use sortBy to sort timezones in UTC offset, 
// and if offset is the same, sort by displayName
const timezonesOrderedByUtcOffset = sortBy(timezones, [
    tzItem => tz.utcOffect,
    'displayName'
]); // This array accepts both a callback and a property name

// Get the latest blog post by first using orderBy to order posts in descending order
const [latestBlogPost] = orderBy(blogposts, 'createdAt', 'desc');
// The second and third arguments can both be arrays as well, e.g.
// Order the blog posts by descending order for creation date, 
// and ascending order for edited date
const orderedPosts = orderBy(blogposts, ['createdAt', 'editedAt'], ['desc', 'asc']);
Enter fullscreen mode Exit fullscreen mode

7. lodash/chunk

Use case: Chunk items when inserting into the sql database to avoid inserting a big amount of data at once.

// Example: Insert over 10,000 people into the person table.
// Chunk the data into 500 chunks first and then insert with a custom insertMany function
const chunkedPeopleData = chunk(peopleData, 500);
await Promise.all(chunkedPeopleData.map(data => 
    insertMany('person', data)
));
Enter fullscreen mode Exit fullscreen mode

8. lodash/sumBy

Decided to use sumBy to wrap up the post ;)

Use case: Get the sum.

// Example: Get total post reads
interface Post {
    name: string;
    viewCount: number;
}

const posts: Post[] = [
    // ...a list of posts
];

const totalPostReads = sumBy(posts, 'viewCount');
Enter fullscreen mode Exit fullscreen mode

That’s It

Those are the Lodash functions I normally reach for, along with their examples. There are debates on whether to use Lodash, given the weight it adds to the application. Additionally, newer versions of Javascript can accomplish a lot more functions that Lodash was trying to simplify. One thing came to mind was flat() that was introduced with ES2019. It handles deep flatten nicely:

const arr = [0, 1, 2, [[[3, 4]]], [[[[5, 6]], [7, 8]]]];
// To turn the above array into [1, 2, 3, 4, 5, 6, 7, 8]:
// Flat deep with ES2019
const flatArr = arr.flat(Infinity);
// Flat deep with lodash
const loFlatArr = flattenDeep(arr);
Enter fullscreen mode Exit fullscreen mode

And many of the above use cases can be achieved by Javascript native function reduce, but I find the Lodash functions provide more communicative APIs. And to reduce (😉) the impact of library weight, I would only import the needed modules:

// Instead of this:
import { isEmpty } from 'lodash';

// Do this:
import isEmpty from 'lodash/isEmpty';
Enter fullscreen mode Exit fullscreen mode

Let me know your thoughts in the comments. Happy Lodashing!

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay