Skip to content

Transforming

How to use

map — project to a new shape

Returns a new collection of the mapped values. The generic type changes when you supply an explicit type parameter.

const names = collect(users).map(u => u.name);
// ImmutableCollection<string>
const dtos = collect(users).map<UserDTO>(u => ({ id: u.id, label: u.name }));

pluck — extract a single field (or subset of fields)

// Single field → flat array of values
collect(users).pluck("name"); // ["Ada", "Bob", "Cid"]
collect(orders).pluck("total.price"); // dot-notation works
// Array of fields → array of objects with only those keys
collect(users).pluck(["id", "name"]);
// [{ id: 1, name: "Ada" }, ...]

select — keep only specific keys on each item

collect(users).select("id", "name", "email");
// Each item is reduced to just those three keys.

groupBy — bucket items by a field value

Returns a collection of group objects. Each group has the grouping key(s) as properties plus an items array containing the members.

collect(users).groupBy("role");
// [
// { role: "admin", items: [...] },
// { role: "user", items: [...] },
// ]
// Multiple keys
collect(orders).groupBy(["year", "month"]);
// [
// { year: 2024, month: 1, items: [...] },
// ...
// ]

To operate on the sub-arrays as collections, wrap them:

collect(users)
.groupBy("department")
.map(g => ({
department: g.department,
headcount: g.items.length,
avgAge: collect(g.items).average("age"),
}));

unique — deduplicate by identity or key

collect([1, 2, 2, 3]).unique(); // [1, 2, 3]
collect(users).unique("email"); // ["a@x", "b@x", ...] — VALUES at the key, not objects

unique("key") returns the VALUES at that key (via pluck + Set). For deduped OBJECTS (one per unique key value), use uniqueList(key) instead.

uniqueList — keep first occurrence (as objects) per key value

Returns the original item objects — one per unique key value, in source order:

collect(products).uniqueList("sku");
// [{ sku: "A", ... }, { sku: "B", ... }, ...]

flat / flatMap — flatten nested arrays

collect([[1, 2], [3, 4]]).flat(); // [1, 2, 3, 4]
collect([[1, [2, [3]]]]).flat(2); // [1, 2, 3]
collect(users).flatMap(u => u.tags); // all tags from all users in one list

collectFrom — hoist a nested array field up

Iterates items, pulls the value at key, and if it is an array, spreads it into the result collection. Useful for flattening one level of nested collections.

collect(orders).collectFrom("lineItems");
// All line items from all orders in a single flat collection.

partition — split into two collections

Returns a tuple [matching, notMatching]:

const [active, inactive] = collect(users).partition(u => u.active);
// active.length + inactive.length === users.length

select columns then chain

collect(users)
.where("active", true)
.select("id", "name")
.sortBy("name")
.all();

Key details / Pitfalls

  • All transform methods return a new collection; the original is untouched.
  • groupBy uses @mongez/reinforcementsgroupBy internally and always names the sub-array property "items".
  • pluck with a string key delegates to reinforcements’ pluck — it uses get(item, key) so dot-notation paths work.
  • map<NewType> changes the TypeScript generic type; downstream chained methods will reflect the new type.
  • collectFrom(key) spreads array values but pushes scalar values as-is — useful only when the nested property is reliably an array.
  • Keyed string operations (appendString, prependString, replaceString, etc.) use cloneForSet internally to shallow-clone plain objects before mutating the key, so the original items are not modified. However, class instances and nested objects are passed through by reference.