“enter map reduce and then some”

The concept of map-reduce and functional approaches to data processing is often associated with languages other than JavaScript. While JavaScript may not be optimal for processing enormous datasets, adopting this mindset provides benefits, especially as functional reactive programming gains popularity in UI development.

This guide demonstrates data-oriented thinking and functional reactive programming approaches through the example of searching complex datasets.

Filter array by content of specific part of its items — step one

The following method searches through a data structure containing DC graphic novel sets and returns universe names of sets containing a specific issue number:

var data = [
  { issues: [1, 2, 3], universe: 'new52' },
  { issues:[66, 77, 88], universe: 'earth one' },
  { issues:[2,11,22,33], universe: 'earth two' },
  { issues:[1,223,334], universe: 'silver age' }
];

var SearchByIssue = function(lookForNumber) {
  return data.filter((set) => {
    return set.issues.some((number) => {
      return number === lookForNumber;
    });
  }).map((set) => set.universe); 
};

The .some() method stops as soon as it finds one truthy result, making this approach optimally efficient.

Filter collection (array) by content of specific part of its items — step two

Consider a more complex scenario: content exists within nested arrays of objects within larger collections:

[{ issues: [{
    id: 32,
    name:"Kingdom Come",
    authors: ["Mark Waid", "Alex Ross"],
    characters: ["Superman, Batman, Diana Prince, Captain Marvel, Spectre, Norman McCay"]
  }...], 
  universe: "alternatives"
},
...]

The task involves searching for all graphic novels featuring a specific character, requiring identification of the collection and issue ID.

Talk is cheap — show me the code

var SearchByCharacter = function(complexData, searchForName) {
  /**
   * Filter filters out array members for which callback returns true,
   * so, we touch the box using .some() and see if it has 
   * stuff that we are looking for inside (some returns true with callback that returns true)
   **/
  return complexData.filter((item) => {
    return item.issues.some((issue) => {
      return (issue.characters.indexOf(searchForName) !== -1);
    });
  })
  /**
   * Now we have all the boxes that have character we are looking for 
   * in any of issues inside.
   *
   * Next we map through the boxes that we found contain some issues
   * we are looking for.
   **/
  .map((box) => {
    /**
     * inside of a box, we are mapping through issues returning
     * array of addresses inside of our big collection,
     * with any other needed info
     */
    return box.issues.map((issue) => {
      return {
        box: box.universe,
        id: issue.id,
        characters: issue.characters
      };
    })
    /**
     * we filter these by character appearance
     * and that is what gets returned per box
     * (array of locations of issues with character appearance in this particular box)
     */
    .filter((issue) => {
      return (issue.characters.indexOf(searchForName) !== -1);
    });
  })
  /**
   * Result is array of arrays of graphic novels with character we are looking for
   * We then reduce these to single array containing them all.
   * 
   * And those are our search results
   **/
  .reduce((a, b) => a.concat(b)); 
};

The example demonstrates that minimal code is required—only higher-order functions and callbacks perform data evaluations. Using functional programming building blocks enables thinking of computations as series of data transformations returning desired results. Importantly, this approach avoids modifying the original data, producing simpler, more readable code structures.

These patterns apply readily to working with data streams and observables, providing an entry point to reactive programming.

A JSbin example is available for testing: http://jsbin.com/vapitux/edit?js,console