Lodash _.groupBy() — Group Arrays & Objects by Key (With Examples)
Share:

Lodash _.groupBy() — Group Arrays & Objects by Key (With Examples)

Amaresh Adak

By Amaresh Adak

Lodash _.groupBy() is a JavaScript utility function that takes a collection (array or object) and groups its elements into an object where the keys are determined by a given criterion and the values are arrays of elements that match that key. It returns a plain object — not a Map or array.

// Quick syntax
_.groupBy(collection, iteratee)

Here is a quick example:

const users = [
  { name: "Alice", department: "Engineering" },
  { name: "Bob", department: "Marketing" },
  { name: "Charlie", department: "Engineering" },
  { name: "Diana", department: "Marketing" }
];

const grouped = _.groupBy(users, 'department');
// Result:
// {
//   Engineering: [{ name: "Alice", ... }, { name: "Charlie", ... }],
//   Marketing: [{ name: "Bob", ... }, { name: "Diana", ... }]
// }

Each element is placed into the group that matches its department value. The original array is not modified.

In this guide, you will learn how to use _.groupBy() to group arrays and objects by property, multiple keys, custom functions, nested values, and computed values. You will also learn how to combine _.groupBy() with other Lodash methods for aggregation and how to achieve the same result with native JavaScript.

🔍 Also check out our guides on Lodash Merge and Lodash SortBy for more data manipulation techniques.

How to Install and Import Lodash groupBy

Install the full library:

npm install lodash

Import _.groupBy() in your code:

// ES6 — import only groupBy (tree-shakable)
import groupBy from 'lodash/groupBy';

// CommonJS
const groupBy = require('lodash/groupBy');

// Or import the full library
import _ from 'lodash';
// then use _.groupBy()

Lightweight alternative — install only the groupBy module:

npm install lodash.groupby
import groupBy from 'lodash.groupby';

Tip: The full Lodash library is ~70KB (minified + gzipped). Importing lodash/groupBy or installing lodash.groupby keeps your bundle lean at ~2KB.

If you are using Lodash in the browser:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
  const result = _.groupBy([6.1, 4.2, 6.3], Math.floor);
  // { '4': [4.2], '6': [6.1, 6.3] }
</script>

Lodash groupBy Syntax and Parameters

Here is the complete syntax:

_.groupBy(collection, [iteratee=_.identity])
ParameterTypeDescription
collectionArray or ObjectThe collection to group.
[iteratee]Function or StringThe criterion for grouping. Can be a property name (string) or a function that returns the group key.
ReturnsObjectAn object where keys are group names and values are arrays of grouped elements.

Important behaviors:

  • The order of grouped values is determined by the order they appear in the original collection
  • The iteratee is called with one argument: (value)
  • If a property value is undefined, it creates a key called "undefined"
  • _.groupBy() does not mutate the original collection

GroupBy a Simple Array

The simplest use case — grouping values using a function:

// Group numbers by their floor value
const grouped = _.groupBy([6.1, 4.2, 6.3], Math.floor);
console.log(grouped);
// Output: { '4': [4.2], '6': [6.1, 6.3] }
// Group strings by their first letter
const words = ["apple", "avocado", "banana", "blueberry", "cherry"];

const grouped = _.groupBy(words, (word) => word[0]);
console.log(grouped);
// Output:
// {
//   a: ["apple", "avocado"],
//   b: ["banana", "blueberry"],
//   c: ["cherry"]
// }
// Group numbers by even/odd
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];

const grouped = _.groupBy(numbers, (n) => n % 2 === 0 ? 'even' : 'odd');
console.log(grouped);
// Output: { odd: [1, 3, 5, 7], even: [2, 4, 6, 8] }

Lodash groupBy Array of Objects

This is the most common use case. Pass a property name as a string to group objects by that property:

const employees = [
  { name: "Alice", department: "Engineering", salary: 95000 },
  { name: "Bob", department: "Marketing", salary: 75000 },
  { name: "Charlie", department: "Engineering", salary: 105000 },
  { name: "Diana", department: "Marketing", salary: 80000 },
  { name: "Eve", department: "Design", salary: 85000 }
];

const byDepartment = _.groupBy(employees, 'department');
console.log(byDepartment);
// Output:
// {
//   Engineering: [
//     { name: "Alice", department: "Engineering", salary: 95000 },
//     { name: "Charlie", department: "Engineering", salary: 105000 }
//   ],
//   Marketing: [
//     { name: "Bob", department: "Marketing", salary: 75000 },
//     { name: "Diana", department: "Marketing", salary: 80000 }
//   ],
//   Design: [
//     { name: "Eve", department: "Design", salary: 85000 }
//   ]
// }

Each employee object is placed intact into its department group. You can then work with each group independently.

Accessing Grouped Results

// Get all engineers
const engineers = byDepartment['Engineering'];
// [{ name: "Alice", ... }, { name: "Charlie", ... }]

// Count per department
const counts = _.mapValues(byDepartment, (group) => group.length);
// { Engineering: 2, Marketing: 2, Design: 1 }

// Get all department names
const departments = Object.keys(byDepartment);
// ["Engineering", "Marketing", "Design"]

GroupBy with a Custom Function

For more complex grouping logic, pass a function instead of a property name:

const products = [
  { name: "Budget Phone", price: 199 },
  { name: "Mid-Range Laptop", price: 799 },
  { name: "Premium Tablet", price: 1299 },
  { name: "Budget Earbuds", price: 49 },
  { name: "Mid-Range Monitor", price: 449 }
];

const byPriceRange = _.groupBy(products, (product) => {
  if (product.price < 100) return 'budget';
  if (product.price < 500) return 'mid-range';
  if (product.price < 1000) return 'premium';
  return 'luxury';
});

console.log(byPriceRange);
// Output:
// {
//   budget: [{ name: "Budget Earbuds", price: 49 }],
//   "mid-range": [{ name: "Budget Phone", price: 199 }, { name: "Mid-Range Monitor", price: 449 }],
//   premium: [{ name: "Mid-Range Laptop", price: 799 }],
//   luxury: [{ name: "Premium Tablet", price: 1299 }]
// }

Group by Date Parts

const orders = [
  { id: 1, date: "2025-01-15", total: 99 },
  { id: 2, date: "2025-01-20", total: 149 },
  { id: 3, date: "2025-02-05", total: 79 },
  { id: 4, date: "2025-02-18", total: 199 },
  { id: 5, date: "2025-03-01", total: 59 }
];

// Group by month
const byMonth = _.groupBy(orders, (order) => order.date.substring(0, 7));
console.log(byMonth);
// Output:
// {
//   "2025-01": [{ id: 1, ... }, { id: 2, ... }],
//   "2025-02": [{ id: 3, ... }, { id: 4, ... }],
//   "2025-03": [{ id: 5, ... }]
// }

Group by Boolean Condition

const tasks = [
  { title: "Write docs", completed: true },
  { title: "Fix bug", completed: false },
  { title: "Deploy", completed: true },
  { title: "Code review", completed: false }
];

const grouped = _.groupBy(tasks, 'completed');
console.log(grouped);
// Output:
// {
//   true: [{ title: "Write docs", ... }, { title: "Deploy", ... }],
//   false: [{ title: "Fix bug", ... }, { title: "Code review", ... }]
// }

// Count completed vs pending
console.log(`Done: ${grouped['true'].length}, Pending: ${grouped['false'].length}`);
// Output: "Done: 2, Pending: 2"

Lodash groupBy Multiple Keys

_.groupBy() natively supports only one key. To group by multiple keys, you have several approaches:

Approach 1: Composite Key String

Concatenate multiple properties into a single key:

const sales = [
  { product: "Widget", region: "North", amount: 100 },
  { product: "Widget", region: "South", amount: 200 },
  { product: "Gadget", region: "North", amount: 150 },
  { product: "Widget", region: "North", amount: 300 },
  { product: "Gadget", region: "South", amount: 250 }
];

const grouped = _.groupBy(sales, (item) => `${item.product}_${item.region}`);
console.log(grouped);
// Output:
// {
//   "Widget_North": [{ product: "Widget", region: "North", amount: 100 }, { ... amount: 300 }],
//   "Widget_South": [{ product: "Widget", region: "South", amount: 200 }],
//   "Gadget_North": [{ product: "Gadget", region: "North", amount: 150 }],
//   "Gadget_South": [{ product: "Gadget", region: "South", amount: 250 }]
// }

Approach 2: Nested GroupBy

Group by the first key, then group each group by the second key:

const byProductThenRegion = _.mapValues(
  _.groupBy(sales, 'product'),
  (productGroup) => _.groupBy(productGroup, 'region')
);

console.log(byProductThenRegion);
// Output:
// {
//   Widget: {
//     North: [{ product: "Widget", region: "North", amount: 100 }, { ... amount: 300 }],
//     South: [{ product: "Widget", region: "South", amount: 200 }]
//   },
//   Gadget: {
//     North: [{ product: "Gadget", region: "North", amount: 150 }],
//     South: [{ product: "Gadget", region: "South", amount: 250 }]
//   }
// }

Approach 3: JSON Key

For more than two keys, serialize as JSON:

const grouped = _.groupBy(sales, (item) =>
  JSON.stringify({ product: item.product, region: item.region })
);

// Access a specific group:
const widgetNorth = grouped[JSON.stringify({ product: "Widget", region: "North" })];

GroupBy Nested Object Properties

To group by a nested property, use a function to access the nested value:

const employees = [
  { name: "Alice", address: { city: "Kolkata", state: "WB" } },
  { name: "Bob", address: { city: "Mumbai", state: "MH" } },
  { name: "Charlie", address: { city: "Pune", state: "MH" } },
  { name: "Diana", address: { city: "Howrah", state: "WB" } }
];

const byState = _.groupBy(employees, (emp) => emp.address.state);
console.log(byState);
// Output:
// {
//   WB: [{ name: "Alice", ... }, { name: "Diana", ... }],
//   MH: [{ name: "Bob", ... }, { name: "Charlie", ... }]
// }

Note: Unlike _.sortBy(), you cannot use dot notation strings like 'address.state' with _.groupBy(). You must use a function.

Combining groupBy with Other Lodash Methods

The real power of _.groupBy() comes from combining it with other Lodash utilities:

GroupBy + sumBy (Aggregate Totals)

const expenses = [
  { category: "Food", amount: 50 },
  { category: "Transport", amount: 30 },
  { category: "Food", amount: 65 },
  { category: "Entertainment", amount: 100 },
  { category: "Transport", amount: 45 }
];

const grouped = _.groupBy(expenses, 'category');
const totals = _.mapValues(grouped, (items) => _.sumBy(items, 'amount'));

console.log(totals);
// Output: { Food: 115, Transport: 75, Entertainment: 100 }

GroupBy + map (Transform Groups)

const orders = [
  { customer: "Alice", item: "Laptop", price: 999 },
  { customer: "Alice", item: "Mouse", price: 29 },
  { customer: "Bob", item: "Keyboard", price: 79 }
];

const grouped = _.groupBy(orders, 'customer');
const summary = _.mapValues(grouped, (orders) => ({
  orderCount: orders.length,
  totalSpent: _.sumBy(orders, 'price'),
  items: orders.map(o => o.item)
}));

console.log(summary);
// Output:
// {
//   Alice: { orderCount: 2, totalSpent: 1028, items: ["Laptop", "Mouse"] },
//   Bob: { orderCount: 1, totalSpent: 79, items: ["Keyboard"] }
// }

GroupBy + maxBy (Find Best in Each Group)

const students = [
  { name: "Alice", subject: "Math", score: 95 },
  { name: "Bob", subject: "Math", score: 88 },
  { name: "Charlie", subject: "Science", score: 92 },
  { name: "Diana", subject: "Science", score: 97 }
];

const grouped = _.groupBy(students, 'subject');
const topStudents = _.mapValues(grouped, (group) => _.maxBy(group, 'score').name);

console.log(topStudents);
// Output: { Math: "Alice", Science: "Diana" }

GroupBy + sortBy (Sort Within Groups)

Need to sort items within each group? Combine _.groupBy() with _.sortBy():

const products = [
  { name: "Widget C", category: "Tools", price: 30 },
  { name: "Widget A", category: "Tools", price: 10 },
  { name: "Gadget B", category: "Electronics", price: 50 },
  { name: "Gadget A", category: "Electronics", price: 20 }
];

const grouped = _.groupBy(products, 'category');
const sortedGroups = _.mapValues(grouped, (items) => _.sortBy(items, 'price'));

// Each category's products are now sorted by price

Handling Edge Cases

Undefined and Null Values

When a property value is undefined or null, _.groupBy() converts it to a string key:

const items = [
  { name: "A", category: "Food" },
  { name: "B", category: undefined },
  { name: "C", category: null },
  { name: "D", category: "Food" }
];

const grouped = _.groupBy(items, 'category');
console.log(grouped);
// Output:
// {
//   Food: [{ name: "A", ... }, { name: "D", ... }],
//   undefined: [{ name: "B", ... }],
//   null: [{ name: "C", ... }]
// }

To handle this gracefully, provide a default in the iteratee:

const grouped = _.groupBy(items, (item) => item.category || 'Uncategorized');
// Now undefined and null items go into "Uncategorized"

Empty Arrays

const grouped = _.groupBy([], 'category');
console.log(grouped);
// Output: {}

_.groupBy() returns an empty object for empty collections — no errors.

Lodash groupBy vs Native JavaScript

Using Object.groupBy() (ES2024)

JavaScript now has a native Object.groupBy() method (Stage 4, available in Node 21+ and modern browsers):

// Native (ES2024)
const grouped = Object.groupBy(users, (user) => user.department);

// Lodash
const grouped = _.groupBy(users, 'department');

Using Array.reduce()

For environments without Lodash or Object.groupBy():

// Native reduce
const grouped = users.reduce((acc, user) => {
  const key = user.department;
  if (!acc[key]) acc[key] = [];
  acc[key].push(user);
  return acc;
}, {});

// Lodash — same result, cleaner syntax
const grouped = _.groupBy(users, 'department');

Comparison Table

Feature_.groupBy()Object.groupBy()Array.reduce()
Syntax_.groupBy(arr, 'key')Object.groupBy(arr, fn)Manual reduce logic
String shorthand'property'❌ Needs function❌ Needs function
Browser supportAll (via npm)ES2024+ / Node 21+All
Bundle size~2KB0KB (native)0KB (native)
Chaining with Lodash✅ Seamless❌ Manual❌ Manual

When to use _.groupBy(): Your project uses Lodash, you need the string shorthand, or you need to support older browsers.

When to use native: You target modern browsers/Node, want zero dependencies, or the grouping logic is simple.

Practical Real-World Examples

E-Commerce: Group Products by Category

const products = [
  { id: 1, name: "Laptop", category: "Electronics", price: 999 },
  { id: 2, name: "T-Shirt", category: "Clothing", price: 29 },
  { id: 3, name: "Headphones", category: "Electronics", price: 199 },
  { id: 4, name: "Jeans", category: "Clothing", price: 59 },
  { id: 5, name: "Novel", category: "Books", price: 15 }
];

const catalog = _.groupBy(products, 'category');

// Render a category sidebar:
Object.entries(catalog).forEach(([category, items]) => {
  console.log(`${category} (${items.length} products)`);
});
// Electronics (2 products)
// Clothing (2 products)
// Books (1 products)

Analytics: Group Events by Date

const pageViews = [
  { url: "/home", timestamp: "2025-02-01T10:00:00Z" },
  { url: "/about", timestamp: "2025-02-01T14:30:00Z" },
  { url: "/home", timestamp: "2025-02-02T09:15:00Z" },
  { url: "/contact", timestamp: "2025-02-02T16:45:00Z" }
];

const byDate = _.groupBy(pageViews, (view) => view.timestamp.split('T')[0]);
const dailyCount = _.mapValues(byDate, (views) => views.length);

console.log(dailyCount);
// { "2025-02-01": 2, "2025-02-02": 2 }

API Response Processing

const apiResponse = [
  { id: 1, status: "success", data: "..." },
  { id: 2, status: "error", message: "Not found" },
  { id: 3, status: "success", data: "..." },
  { id: 4, status: "error", message: "Timeout" }
];

const { success = [], error = [] } = _.groupBy(apiResponse, 'status');

console.log(`${success.length} succeeded, ${error.length} failed`);
// "2 succeeded, 2 failed"

// Handle errors
error.forEach(e => console.error(`Request ${e.id}: ${e.message}`));

Tip: If your API returns partial data across multiple requests, use _.merge() to deep merge responses before grouping them.

Performance Considerations

_.groupBy() iterates through the collection once:

  • Time complexity: O(n) — where n is the number of elements
  • Space complexity: O(n) — creates a new object with all elements distributed into groups

Tips:

  • _.groupBy() is highly efficient for its purpose — a single pass O(n) operation
  • For very large datasets (1M+ items), consider processing in chunks or using a streaming approach
  • The iteratee function should be lightweight — avoid expensive computations inside it
  • If you need to group and then immediately transform, chain the operations to avoid multiple passes:
// ✅ Efficient — groups and transforms in two passes
const result = _.mapValues(_.groupBy(data, 'category'), (items) => items.length);

// ❌ Inefficient — groups, then iterates groups, then iterates each group
const grouped = _.groupBy(data, 'category');
const result = {};
for (const key in grouped) {
  result[key] = 0;
  for (const item of grouped[key]) {
    result[key]++;
  }
}

FAQs

What is Lodash groupBy and how does it work?

_.groupBy() is a Lodash function that takes a collection (array or object) and a criterion (property name or function), then returns an object where keys are group names and values are arrays of elements matching that key. It iterates through the collection once, placing each element into the appropriate group based on the iteratee's return value.

Can I group by multiple keys with Lodash groupBy?

_.groupBy() natively supports only one key. For multiple keys, you can create a composite key string (_.groupBy(arr, (x) => x.key1 + '_' + x.key2)), use nested groupBy calls (_.mapValues(_.groupBy(arr, 'key1'), (g) => _.groupBy(g, 'key2'))), or serialize keys as JSON.

Does Lodash groupBy handle undefined or null values?

Yes. When a grouping key is undefined or null, _.groupBy() creates string keys "undefined" or "null" respectively. To handle these gracefully, use a function with a default: _.groupBy(arr, (x) => x.category || 'Uncategorized').

What is the difference between Lodash groupBy and partition?

_.groupBy() splits a collection into multiple groups based on any criterion. _.partition() splits a collection into exactly two groups — items that match a predicate and items that don't. Use _.partition() when you only need a true/false split.

Is there a native JavaScript alternative to Lodash groupBy?

Yes. Object.groupBy() was introduced in ES2024 and is available in Node 21+ and modern browsers. For older environments, Array.prototype.reduce() can achieve the same result. However, _.groupBy() offers cleaner syntax with string property shorthands and integrates seamlessly with other Lodash utilities.

Does Lodash groupBy mutate the original array?

No. _.groupBy() returns a new object containing references to the original elements. The original collection is never modified. However, the elements inside each group are the same references — not deep copies — so modifying an element in a group will also modify it in the original array.

Ready to Implement This in Production?

Skip the months of development and debugging. Our team will implement this solution with enterprise-grade quality, security, and performance.

Web Apps ₹25K+
Mobile Apps ₹75K+