Introduction
Collections are a super powerful class that aims to manage your arrays easily and lift the heavy work from your shoulders.
Philosophy
Working with arrays especially complex arrays can really be a pain, thus there was a need to handle working with these arrays.
Collections are Immutable
which means the original array is never modified, instead a new array is created and returned, also any chained method generates a new array and so one.
Any collection automatically has all internal Arrays methods available to it, so you can use any of the Array methods on a collection also each method of it will return a new instance, for example map
will return a new collection instead of array.
It can deal with Numbers
, Strings
Objects
and make massive filtering and sorting a breeze, so enough talking and let's get starting.
Installation
npm install @mongez/collection
Using Yarn
yarn add @mongez/collection
Usage
import { collect } from "@mongez/collection";
const collection = collect([1, 2, 3, 4, 5]);
const filtered = collection.filter((item) => item > 2);
Sounds simple right? but it's much more than that, let's see what else we can do with it.
Working With Math And Numbers
Collections are shipped with many math utilities that will help you perform math operation quickly, let's see it in action
import { collect } from "@mongez/collection";
const collection = collect([1, 2, 3, 4, 5]);
const sum = collection.sum(); // 15
const average = collection.average(); // 3
const max = collection.max(); // 5
const min = collection.min(); // 1
const median = collection.median(); // 3
Pretty nice, oh there is more, let's make some math operations on the collection
import { collect } from "@mongez/collection";
const collection = collect([1, 2, 3, 4, 5]);
const multipliedNumbers = collection.multiply(2); // [2, 4, 6, 8, 10]
// or we can use `double` method to double the values directly
const doubledNumbers = collection.double(); // [2, 4, 6, 8, 10]
const dividedNumbers = collection.divide(2); // [0.5, 1, 1.5, 2, 2.5]
// or we can use `half` method to half the values directly
const halfNumbers = collection.half(); // [0.5, 1, 1.5, 2, 2.5]
const plusNumbers = collection.plus(2); // [3, 4, 5, 6, 7]
// we can also increment the values directly
const incrementedNumbers = collection.increment(); // [2, 3, 4, 5, 6]
const minusNumbers = collection.minus(2); // [-1, 0, 1, 2, 3]
// we can also decrement the values directly
const decrementedNumbers = collection.decrement(); // [0, 1, 2, 3, 4]
The amazing thing here is that we can do it as well if the array is an array of objects over certain key.
import { collect } from "@mongez/collection";
const collection = collect([
{ id: 1, price: 10 },
{ id: 2, price: 20 },
{ id: 3, price: 30 },
{ id: 4, price: 40 },
{ id: 5, price: 50 },
]);
const sum = collection.sum("price"); // 150
const average = collection.average("price"); // 30
const max = collection.max("price"); // 50
const min = collection.min("price"); // 10
const median = collection.median("price"); // 30
This can be also done with math operations
import { collect } from "@mongez/collection";
const collection = collect([
{ id: 1, price: 10 },
{ id: 2, price: 20 },
{ id: 3, price: 30 },
{ id: 4, price: 40 },
{ id: 5, price: 50 },
]);
const multipliedNumbers = collection.multiply("price", 2); // [20, 40, 60, 80, 100]
// or we can use `double` method to double the values directly
const doubledNumbers = collection.double("price"); // [20, 40, 60, 80, 100]
const dividedNumbers = collection.divide("price", 2); // [5, 10, 15, 20, 25]
// or we can use `half` method to half the values directly
const halfNumbers = collection.half("price"); // [5, 10, 15, 20, 25]
const plusNumbers = collection.plus("price", 2); // [12, 22, 32, 42, 52]
// we can also increment the values directly
const incrementedNumbers = collection.increment("price"); // [11, 21, 31, 41, 51]
const minusNumbers = collection.minus("price", 2); // [8, 18, 28, 38, 48]
// we can also decrement the values directly
const decrementedNumbers = collection.decrement("price"); // [9, 19, 29, 39, 49]
Working With Strings
Collections are also shipped with many string utilities that will help you perform string operations quickly, let's see it in action
import { collect } from "@mongez/collection";
const collection = collect(["Hello", "World", "How", "Are", "You"]);
const appendedString = collection.appendString("!!!"); // ["Hello!!!", "World!!!", "How!!!", "Are!!!", "You!!!"]
const prependedString = collection.prependString("!!!"); // ["!!!Hello", "!!!World", "!!!How", "!!!Are", "!!!You"]
const replacedString = collection.replaceString("Hello", "Hi"); // ["Hi", "World", "How", "Are", "You"]
const removeString = collection.removeString("H"); // ["ello", "World", "ow", "Are", "You"]
Working With Objects
Let's go deeper, and start dealing with objects.
Plucking Objects
import { collect } from "@mongez/collection";
const collection = collect([
{ id: 1, name: "John" },
{ id: 2, name: "Doe" },
{ id: 3, name: "Jane" },
{ id: 4, name: "Doe" },
{ id: 5, name: "John" },
]);
const plucked = collection.pluck("name"); // ["John", "Doe", "Jane", "Doe", "John"]
We can also pluck multiple keys by passing an array of keys
import { collect } from "@mongez/collection";
const collection = collect([
{ id: 1, name: "John", age: 20 },
{ id: 2, name: "Doe", age: 30 },
{ id: 3, name: "Jane", age: 40 },
{ id: 4, name: "Doe", age: 50 },
{ id: 5, name: "John", age: 60 },
]);
const plucked = collection.pluck(["name", "age"]); // [["John", 20], ["Doe", 30], ["Jane", 40], ["Doe", 50], ["John", 60]]
The Mighty where
Method
The where
method is the most powerful method in the collection, it allows you to filter the collection based on a list of predefined operations which will make it easier to filter the collection.
import { collect } from "@mongez/collection";
const collection = collect([
{ id: 1, name: "John", age: 20 },
{ id: 2, name: "Doe", age: 30 },
{ id: 3, name: "Jane", age: 40 },
{ id: 4, name: "Doe", age: 50 },
{ id: 5, name: "John", age: 60 },
{id: 6, position: 'developer', salary: 1000 },
]);
const filtered = collection.where("age", ">", 30); // [{ id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
const filtered = collection.where("age", "<", 30); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }]
const filtered = collection.where("age", ">=", 30); // [{ id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
const filtered = collection.where("age", "<=", 30); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }]
const filtered = collection.where("age", "=", 30); // [{ id: 2, name: "Doe", age: 30 }]
// not equal operator
const filtered = collection.where("age", "!=", 30); // [{ id: 1, name: "John", age: 20 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
// in operator
const filtered = collection.where("age", "in", [30, 40]); // [{ id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }]
// not in operator
const filtered = collection.where("age", "not in", [30, 40]); // [{ id: 1, name: "John", age: 20 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
// between operator, alias is `<>` can also be used with dates
const filtered = collection.where("age", "between", [30, 40]); // [{ id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }]
// not between operator, can also be used as !<>
const filtered = collection.where("age", "not between", [30, 40]); // [{ id: 1, name: "John", age: 20 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
// like operator
const filtered = collection.where("name", "like", "Do"); // [{ id: 2, name: "Doe", age: 30 }, { id: 4, name: "Doe", age: 50 }]
// not like operator
const filtered = collection.where("name", "not like", "Do"); // [{ id: 1, name: "John", age: 20 }, { id: 3, name: "Jane", age: 40 }, { id: 5, name: "John", age: 60 }]
// exists operator
const filtered = collection.where("salary", "exists"); // [{id: 6, position: 'developer', salary: 1000 }]
// not exists operator
const filtered = collection.where("salary", "not exists"); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
// is operator
const filtered = collection.where("salary", "is", undefined); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]
// is not operator
const filtered = collection.where("salary", "is not", undefined); // [{id: 6, position: 'developer', salary: 1000 }]
You can see all operators here in action, there are over 30
operators to be used!
Single Values
There are also some good methods that handles single values.
import { collect } from "@mongez/collection";
const collection = collect([
{ id: 1, name: "John", age: 20 },
{ id: 2, name: "Doe", age: 30 },
{ id: 3, name: "Jane", age: 40 },
{ id: 4, name: "Doe", age: 50 },
{ id: 5, name: "James", age: 60 },
]);
// get first item
const first = collection.first(); // { id: 1, name: "John", age: 20 }
// get last item
const last = collection.last(); // { id: 5, name: "James", age: 60 }
// get random item
const random = collection.random(); // { id: 2, name: "Doe", age: 30 }
// get value using dot notation for specific index and key
const value = collection.get("0.name"); // "John"
// get first available value for the given key
const value = collection.value("name"); // "John"
// get last available value for the given key
const value = collection.lastValue("name"); // "James"
Element Positions
In this section we will see how to change the position of elements in the collection.
Swap
Using swap
method will allow you swap between two indexes in the collection
const numbers = collect([1, 2, 3, 4, 5]);
numbers.swap(0, 4); // [5, 2, 3, 4, 1]
Moving Elements
Using move
method will allow you move an element from one index to another.
const numbers = collect([1, 2, 3, 4, 5]);
numbers.move(0, 4); // [2, 3, 4, 5, 1]
Shuffling
The shuffle
method will randomly shuffle the items in the collection.
const numbers = collect([1, 2, 3, 4, 5]);
numbers.shuffle(); // something like [2, 5, 1, 4, 3]
Reverse
The reverse
method will reverse the order of the collection's items.
const numbers = collect([1, 2, 3, 4, 5]);
numbers.reverse(); // [5, 4, 3, 2, 1]
flip
method is an alias toreverse
method.
Reordering
The reorder
method will reorder the items in the collection using the given keys.
const numbers = collect([1, 2, 3, 4, 5, 6, 7]);
numbers.reorder({
0: 3,
1: 4,
2: 5,
3: 6,
4: 0,
5: 1,
6: 2,
}); // [5, 6, 7, 1, 2, 3, 4]
It receives an object, the key is the old index, and its value is the new index.
Grouping Values
Another useful feature is grouping values, you can group values by a key.
const users = collect([
{ name: "Ahmed", age: 20 },
{ name: "Mohamed", age: 25 },
{ name: "Ali", age: 30 },
{ name: "Hasan", age: 30 },
]);
users.groupBy("age");
// [
// {
// age: 20,
// data: [{ name: "Ahmed", age: 20 }],
// },
// {
// age: 25,
// data: [{ name: "Mohamed", age: 25 }],
// },
// {
// age: 30,
// data: [
// { name: "Ali", age: 30 },
// { name: "Hasan", age: 30 },
// ],
// },
// ]
It basically creates a new array of objects, each object contains the key and the items that have the same value for that key will be added in data
key for that grouped data.
Group By Multiple Keys
You can also group the collection by multiple keys.
const studentsClasses = collect[
{
id: 1,
class: "A",
grade: 1,
},
{
id: 2,
class: "B",
grade: 2,
},
{
id: 3,
class: "A",
grade: 3,
},
{
id: 4,
class: "B",
grade: 2,
},
{
id: 5,
class: "B",
grade: 2,
},
{
id: 6,
class: "C",
grade: 5,
},
]);
studentsClasses.groupBy(["class", "grade"]);
// [
// {
// class: "A",
// grade: 1,
// items: [
// {
// id: 1,
// class: "A",
// grade: 1,
// },
// ],
// },
// {
// class: "B",
// grade: 2,
// items: [
// {
// id: 2,
// class: "B",
// grade: 2,
// },
// {
// id: 4,
// class: "B",
// grade: 2,
// },
// {
// id: 5,
// class: "B",
// grade: 2,
// },
// ],
// },
// {
// class: "A",
// grade: 3,
// items: [
// {
// id: 3,
// class: "A",
// grade: 3,
// },
// ],
// },
// {
// class: "C",
// grade: 5,
// items: [
// {
// id: 6,
// class: "C",
// grade: 5,
// },
// ],
// },
// ]
Defining other key for grouped data
By default, the grouped data will be added in data
key, but you can change that by passing the second argument to the groupBy
method.
const users = collect([
{ name: "Ahmed", age: 20 },
{ name: "Mohamed", age: 25 },
{ name: "Ali", age: 30 },
{ name: "Hasan", age: 30 },
]);
users.groupBy("age", "students");
// [
// {
// age: 20,
// students: [{ name: "Ahmed", age: 20 }],
// },
// {
// age: 25,
// students: [{ name: "Mohamed", age: 25 }],
// },
// {
// age: 30,
// students: [
// { name: "Ali", age: 30 },
// { name: "Hasan", age: 30 },
// ],
// },
// ]
Sorting
There are also some good sort methods that will make it easier for you to sort arrays of objects.
the original
sort
method of array will return a new collection of the sorted data as well.
sortBy
The sortBy
method sorts the collection's items by a given key.
const users = collect([
{ name: "Ahmed", age: 20 },
{ name: "Mohamed", age: 25 },
{ name: "Ali", age: 30 },
{ name: "Hasan", age: 30 },
]);
users.sortBy("age"); // [{ name: "Ahmed", age: 20 }, { name: "Mohamed", age: 25 }, { name: "Ali", age: 30 }, { name: "Hasan", age: 30 }]
sortByDesc
The sortByDesc
method sorts the collection's items by a given key in descending order.
const users = collect([
{ name: "Ahmed", age: 20 },
{ name: "Mohamed", age: 25 },
{ name: "Ali", age: 30 },
{ name: "Hasan", age: 30 },
]);
users.sortByDesc("age"); // [{ name: "Ali", age: 30 }, { name: "Hasan", age: 30 }, { name: "Mohamed", age: 25 }, { name: "Ahmed", age: 20 }]
Sort By Multiple Keys
You can also sort the collection by multiple keys using sortBy
.
const users = collect([
{ name: "Jane", age: 25 },
{ name: "Jack", age: 30 },
{ name: "Ali", age: 20 },
{ name: "Hasan", age: 20 },
{ name: "Hasan", age: 19 },
]);
users.sortBy({
age: "asc",
name: "asc",
}); // [{ name: "Hasan", age: 19 }, { name: "Ali", age: 20 }, { name: "Hasan", age: 20 }, { name: "Jane", age: 25 }, { name: "Jack", age: 30 }]
The method receives an object, the key will be the sorting key and its value is either asc
or desc
for ascending or descending order.
Unique Values
Let's get some unique values from the array.
Unique
The unique
method will remove any duplicate values from the collection.
const numbers = collect([1, 2, 3, 4, 5, 5, 5]);
numbers.unique(); // [1, 2, 3, 4, 5]
We can also get the unique values of specific key.
const users = collect([
{ id: 1, name: "John" },
{ id: 2, name: "John" },
{ id: 3, name: "Jane" },
]);
users.unique("name"); // ["John", "Jane"]
Unique List
The uniqueList
method will return all unique elements for the given value, so the key will be matched against the uniqueness criteria, and the first unique value will return the entire object instead of just the value itself.
const users = collect([
{ id: 1, name: 'John' },
{ id: 2, name: 'John' },
{ id: 3, name: 'Jane' },
]);
users.uniqueList('name'); // [{ id: 1, name: 'John' }, { id: 3, name: 'Jane' }]
Adding Unique Values
Unique values can be added to the array if any of these values are not listed in the array using pushUnique
to add unique value at the end of the array, and prependUnique
to add unique value at the beginning of the array.
const numbers = collect([1, 2, 3, 4, 5]);
numbers.pushUnique(6, 1, 4); // [1, 2, 3, 4, 5, 6]
numbers.prependUnique(0, 2, ,3); // [0, 1, 2, 3, 4, 5]
Indexes
Let's play with indexes, shall we :)
const users = collect([
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
{ id: 3, name: "Ali" },
]);
// get all indexes in a collection
users.indexes(); // [0, 1, 2]
// get the value of a specific index
users.at(2); //
// get all elements in even indexes
users.evenIndexes(); // [{ id: 1, name: "John" }, { id: 3, name: "Ali" }]
// get all elements in odd indexes
users.oddIndexes(); // [{ id: 2, name: "Jane" }]
// get all items except the given indexes
users.exceptIndexes(0, 2); // [{ id: 2, name: "Jane" }]
// get only the given indexes
users.onlyIndexes(0, 2); // [{ id: 1, name: "John" }, { id: 3, name: "Ali" }]
Taking And Skipping
Let's take some items from the array.
Taking Items
The take
method returns a new collection with the specified number of items.
const users = collect([
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
{ id: 3, name: "Ali" },
]);
users.take(2); // [{ id: 1, name: "John" }, { id: 2, name: "Jane" }]
users.takeLast(2); // [{ id: 2, name: "Jane" }, { id: 3, name: "Ali" }]
users.takeWhile((user) => user.id < 3); // [{ id: 1, name: "John" }, { id: 2, name: "Jane" }]
users.takeUntil((user) => user.id === 2); // [{ id: 1, name: "John" }]
Skipping items
The skip
method returns a new collection with the specified number of items removed from the beginning.
const users = collect([
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
{ id: 3, name: "Ali" },
]);
users.skip(2); // [{ id: 3, name: "Ali" }]
users.skipLast(2); // [{ id: 1, name: "John" }]
users.skipWhile((user) => user.id < 3); // [{ id: 3, name: "Ali" }]
users.skipUntil((user) => user.id === 2); // [{ id: 3, name: "Ali" }]
Counting
Let's count some values and items.
Getting collection length
The length
property will return the number of items in the collection.
const numbers = collect([1, 2, 3, 4, 5]);
numbers.length; // 5
Counting values
The countValue
method will return the number of occurrences for the given value.
const numbers = collect([1, 2, 3, 4, 5, 2]);
numbers.countValue(2); // 2
Counting Value for key
The count
method will return the number of occurrences for the given key and value.
const users = collect([
{ name: 'John', age: 20 },
{ name: 'Jane', age: 25 },
{ name: 'Jack', age: 30 },
{ name: 'Jill' },
]);
users.count('age'); // 3
Counting each value for the given key
The countBy
method will return the number of occurrences for each value of the given key.
const users = collect([
{ name: 'John', age: 20 },
{ name: 'Jane', age: 25 },
{ name: 'Jack', age: 30 },
{ name: 'Jill' },
]);
users.countBy('age'); // { 20: 1, 25: 1, 30: 1 }
Iterating
Collections are iterable
, so you can loop over it using for...of
loop.
const numbers = collect([1, 2, 3, 4, 5]);
for (const number of numbers) {
console.log(number);
}
Getting array values
To convert the collection into an array, you can use the all
method.
const numbers = collect([1, 2, 3, 4, 5]);
numbers.all(); // [1, 2, 3, 4, 5]
toArray
is an alias ofall
method.
Merge
The merge
method will merge the given array or collection with the original collection.
const numbers = collect([1, 2, 3, 4, 5]);
const merged = numbers.merge([6, 7, 8, 9, 10]); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
It can also merge another collection
const numbers = collect([1, 2, 3, 4, 5]);
const merged = numbers.merge(collect([6, 7, 8, 9, 10])); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
concat
is an alias ofmerge
method.
Collecting all data from certain key
The collectFrom
method will allow you to collect items from a given key of each element.
const users = collect([
{ name: 'John', age: 20, pets: ['dog', 'cat'] },
{ name: 'Jane', age: 25, pets: ['dog', 'cat'] },
{ name: 'Jack', age: 30, pets: ['dog', 'cat'] },
{ name: 'Jill', age: 35, pets: ['dog', 'cat'] },
]);
users.collectFrom('pets'); // ['dog', 'cat', 'dog', 'cat', 'dog', 'cat', 'dog', 'cat']
Collecting from certain key only
The collectFromKey
method allow you to create a new collection from the given key directly, the key supports dot notation, starting with the index.
const users = collect([
{ name: 'John', age: 20, pets: ['dog', 'cat'] },
{ name: 'Jane', age: 25, pets: ['dog', 'cat'] },
{ name: 'Jack', age: 30, pets: ['dog', 'cat'] },
{ name: 'Jill', age: 35, pets: ['dog', 'cat'] },
]);
users.collectFromKey('0.pets'); // ['dog', 'cat']
Collecting from iterators
The collect
function can be used to convert an iterable into a collection using collect.fromIterator
method.
const numbers = collect.fromIterator([1, 2, 3, 4, 5].values());
Create empty collection
The collect
function can also be used to create an empty collection using collect.create(length: number, initialValue: any)
method.
const numbers = collect.create(10); // [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
You can also specify the initial value.
const numbers = collect.create(10, 0); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Also specify initial value based on index.
const numbers = collect.create(10, (index) => index); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Conclusion
At the end, i hope you enjoyed the article, and i hope you will find it useful.
Collection is a very useful tool, and i hope you will use it in your projects.
The article doesn't cover all the methods, you can read the entire documentation of it in the Repository Page.
Feel free to give me a comment and feedback, and if you have any questions, feel free to ask.
Thanks for reading.
Top comments (2)
Thanks for the post. So, when we use these functions, it will mutate the original array or it will make a clone array?
They are all
Immutable
so the original array is kept untouched.