Lodash _.minBy() method
What you’ll learn
- How
_.minBy(array, iteratee)resolves tobaseExtremum(array, baseIteratee(iteratee, 2), baseLt)— the same engine as_.maxBy, opposite comparator. - Two iteratee shapes: a function or a
_.propertypath string ('n','price.base'). - What gets skipped: rows whose iteratee returns
null,undefined, orNaN; the Symbol-position rule inherited from_.min. - Tie-breaking: the first element with the minimum score wins.
- That empty / null input returns
undefined— default with??, not||.
Prerequisites
Read _.min() first—_.minBy is the same factory with an iteratee plugged in. The skip rules and Symbol-position quirks documented there all apply here.
- Iteratee shorthand: string → property path; function → itself; object → partial match.
- baseExtremum loop: single pass, strict
<, first-element-wins on ties.
Overview
Each element flows through baseIteratee(iteratee, 2) to produce a score. The score is the comparison key; the original element is what comes back. Inside the seed guard, any score that is null, undefined, NaN, or a Symbol fails to seed—those rows quietly drop out. Once seeded, baseLt (value < computed) decides replacements.
Score, not return
The iteratee picks the comparison key. _.minBy returns the original element, not the score.
Path shorthand
Dotted paths like 'price.base' drill into nested objects via _.property.
Missing fields skip
Rows where the path returns undefined are silently excluded—the comparison runs only on rows with the field.
Syntax
_.minBy(array, [iteratee = _.identity]) - array: array to scan. Falsy / empty short-circuits to
undefined. - iteratee: function or string property path. Default is
_.identity—omit it on a plain-number array and you’ll get the same result as_.min(array). - Returns: the original element with the lowest projected score, or
undefined.
Docs baseline — function, path, nested path
The function form and the _.property shorthand are interchangeable. Dotted paths drill into nested objects.
import minBy from "lodash/minBy";
const objects = [{ n: 1 }, { n: 2 }];
console.log(minBy(objects, function (o) { return o.n; })); // { n: 1 }
console.log(minBy(objects, "n")); // { n: 1 }
// Real-world: cheapest after discount
const products = [
{ name: "Laptop", price: { base: 800, discount: 50 } },
{ name: "Smartphone", price: { base: 600, discount: 30 } },
{ name: "Tablet", price: { base: 400, discount: 20 } }
];
console.log(minBy(products, p => p.price.base - p.price.discount));
// { name: "Tablet", price: { base: 400, discount: 20 } }
// Nested path shorthand
const temperatures = [
{ location: "City A", temperature: -5 },
{ location: "City B", temperature: 2 },
{ location: "City C", temperature: -10 }
];
console.log(minBy(temperatures, "temperature"));
// { location: "City C", temperature: -10 } Missing fields, NaN, and ties
Rows missing the field are silently dropped from the contest (unlike _.meanBy, this gives the correct answer for the rows that have the field). NaN scores are skipped. Ties go to the first occurrence.
import minBy from "lodash/minBy";
// Missing field: silently skipped, still gets a correct min
console.log(minBy([{ n: 1 }, { x: 2 }, { n: 3 }], "n"));
// { n: 1 }
// Every row missing the field -> undefined
console.log(minBy([{ x: 1 }, { y: 2 }], "n"));
// undefined
// NaN scores are skipped
console.log(minBy([{ n: 5 }, { n: NaN }, { n: 1 }], "n"));
// { n: 1 }
// Ties: first occurrence wins (strict <)
console.log(minBy(
[{ id: 1, n: 5 }, { id: 2, n: 3 }, { id: 3, n: 3 }],
"n"
));
// { id: 2, n: 3 } Empty input, default iteratee, BigInt & Symbols
Empty / null returns undefined. Omitting the iteratee falls back to _.identity—great for plain numeric arrays, useless for objects. BigInts compare normally; Symbol scores follow _.min’s position rule.
import minBy from "lodash/minBy";
console.log(minBy([], "n")); // undefined
console.log(minBy(null, "n")); // undefined
// Safe default with ??, not || (in case the min element has a falsy property)
const cheapest = minBy([], "price") ?? { price: Infinity };
console.log(cheapest); // { price: Infinity }
// No iteratee -> _.identity. Works for numbers, fails on objects.
console.log(minBy([5, 3, 8, 1, 4])); // 1 (acts like _.min)
console.log(minBy([{ n: 3 }, { n: 1 }])); // { n: 3 }
// ^ first object stays seeded:
// {n:1} < {n:3} is false (NaN)
// BigInt scores compare fine
console.log(minBy([{ n: 3n }, { n: 1n }, { n: 5n }], "n"));
// { n: 1n }
// Symbol after a seed throws (just like _.min)
try {
console.log(minBy([{ n: 1 }, { n: Symbol("x") }, { n: 3 }], "n"));
} catch (err) {
console.log("Threw:", err.message); // "Cannot convert a Symbol value to a number"
} 📋 _.minBy vs _.min vs hand-rolled reduce
| Approach | Code | Notes |
|---|---|---|
| _.min | _.min(arr) | Single-arg only; second argument is ignored. Compares values directly. |
| _.minBy (function) | _.minBy(arr, o => o.price) | Most flexible; iteratee can compute derived values like p.base - p.discount. |
| _.minBy (path) | _.minBy(arr, 'price.base') | Shorter; dotted paths supported via _.property. |
| Reduce | arr.reduce((m, o) => o.price < m.price ? o : m) | Verbose; throws on empty; no NaN/undefined guard. |
Pitfalls to avoid
Use ??
_.minBy(arr, 'n') || fallback is safer than for primitives (the return is an object, so usually truthy), but a null return from an empty array is still falsy. Prefer ?? or explicit === undefined.
Silent partial answers
Rows missing the field don’t throw and don’t poison the result—they just disappear. If you wanted a hard failure, validate the data first.
One argument only
The iteratee is invoked with (value)—no index, no array. Use reduce if you need them.
Order matters
When two elements tie for the minimum score, the first one wins. Sort or pre-filter if you need a different tie-breaker.
Position rule applies
A Symbol score that appears after a non-Symbol seed will throw Cannot convert a Symbol value to a number. Filter symbols out of the data if they might appear.
❓ FAQ
Summary
- Purpose: find the “smallest” element by a derived score; returns the original element.
- Remember: function or string-path iteratee; missing/null/undefined/NaN scores silently skipped; ties keep first occurrence; empty/null →
undefined. - Next: Lodash _.multiply() for pairwise multiplication, or read the official Lodash docs for _.minBy.
_.minBy calls the iteratee with the documented arity hint (baseIteratee(iteratee, 2))—that's what lets 'price.base' drill into nested objects exactly like _.get(o, 'price.base') would, with no extra parsing on your end.
6 people found this page helpful
