How do you chain functions using lodash?

JavascriptLodash

Javascript Problem Overview


I have an object that looks like

var foundUser = {
    charData: []
}

which then I load an object from a database using mysql and then I call

_.assignIn(foundUser, rows[0]);

But I get a few extra properties that I don't need (this isn't solvable by using select)

So I call

foundUser = _.omit(foundUser, ['blah']);

But it would be nice if I could just do

_.assignIn(foundUser, rows[0]).omit(rows[0], ['blah']);

But that throws an error, am I doing it wrong or is there another way this can be done?

Javascript Solutions


Solution 1 - Javascript

To chain with lodash, you first have to wrap the object:

_(foundUser).assignIn(rows[0]).omit(['blah']).value();

Further clarification:

The _ creates a lodash object which allows for implicit method chaining. Implicit method chaining means that in certain circumstances it may return a primitive value, in others it may return a lodash object that you need to unwrap by calling .value() on it.

If you'd use _.chain(...), you'd be creating a lodash object with explicit method chaining. The result is always a wrapped value and always needs to be unwrapped by calling .value() on it.

For further reference here are the links to the documentation:

Explicit chaining in Lodash

Implicit chaining in Lodash

Solution 2 - Javascript

As an alternative to the wrap-chain-unwrap pattern (nothing inherently wrong with it, but alternatives are always interesting) there's another way you can check.

Try by leveraging _.flow.

The idea is that every function inside flow will receive as input the output of the previous one, which is exactly what you need. An example, given this data:

var foundUser = {
    charData: []
};

var rows = [{ok: 1, blah: 'nope'}];

Using Lodash FP we can pass the data as last argument. This feature along with the auto-currying of each method in Lodash/fp makes our life easier when composing functions. This means we can have this succinct and expressive code:

_.flow(
 _.assign(rows[0]),
 _.omit('blah')
)(foundUser);

// >> {"charData":[],"ok": 1}

Using the standard version of Lodash we have to curry those functions ourselves using _.partial, and the code will certainly look less terse, but it is still possible to do so:

_.flow(
 _.partialRight(_.assign, rows[0]),
 _.partialRight(_.omit, 'blah')
)(foundUser);

// >> {"charData":[],"ok": 1}

A great benefit of using flow rather than chaining is that you can easily mix Lodash methods with your own custom functions, since - as said - all they need is just data as input and data as output, and nothing else:

const yourFunction = d => ({ ...d, yourProp: 4 });

_.flow(
 _.assign(rows[0]),
 yourFunction,
 _.omit('blah')
)(foundUser);

// >> {"charData":[],"ok": 1, yourProp: 4}

This makes function composition much easier and more flexible and arguably will naturally lead to more expressive code.

Another thing to note. If you are installing and importing only the Lodash methods you use, you will have to add just the flow package and not the whole Lodash library as you'd do with chaining.

npm i --save lodash.flow

Vs

npm i --save lodash

Perhaps a negligible advantage in many real-world applications where having the full build of Lodash is not a problem and arguably easier to maintain up to date, but very handy in case you are writing a library or a script that will be distributed to use as a third party tool. In that case you will be able to keep your footprint way lower in terms of distributed size.

Lodash methods docs:

Articles worth checking out:

A few other things to note:

  • In Lodash/fp Flow is aliased as _.pipe, so you can pick whichever you prefer.

  • You can also use _.flowRight (or its fp alias _.compose) if you prefer right to left composition, as seen in Ramda's compose.

Example:

_.flow(
 _.assign(rows[0]), // #1st to execute
 yourFunction,  // #2
 _.omit('blah'),  // #3
)(foundUser);

// is the same as...

_.flowRight(
 _.omit('blah'), // #3rd to execute
 yourFunction, // #2
 _.assign(rows[0]), // #1
)(foundUser);

Solution 3 - Javascript

Have you ever tried lodash/fp? It comes with all the same functions, but they are curried and none of them mutates the input.

Because of that, you can compose them in a really nice way.

Example:

import moment from 'moment'
import { compose, filter, groupBy, size, sortBy } from 'lodash/fp'

const fromAdmin = filter({ type: 'admin' })
const groupedByDate = groupBy(message => moment(message.createdAt).format('YYYYMMDD'))
const sorted = sortBy('createdAt')
const unreadByUser = filter({ isReadByUser: false })

const groupedMessages = compose(
  groupedByDate,
  sorted,
  unreadByUser,
  fromAdmin,
)(messages)

Solution 4 - Javascript

Chain is the best equivalence to pipe in lodash.

_.chain(foundUser)
 .assignIn(rows[0])
 .omit(['blah'])
 .value()

You can also chain some custom function by .tap or .thru, e.g.:

_.chain(foundUser)
 .assignIn(rows[0])
 .tap(console.log)
 .omit(['blah'])
 .value()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDatsikView Question on Stackoverflow
Solution 1 - JavascriptKennethView Answer on Stackoverflow
Solution 2 - JavascriptAurelioView Answer on Stackoverflow
Solution 3 - JavascriptDanielView Answer on Stackoverflow
Solution 4 - JavascriptPhuhuiView Answer on Stackoverflow