Reduce any JSON value by traversing depth first and visiting each node

Downloads in past


3.0.0a year ago6 years agoMinified + gzip package size for json-reduce in KB


Reduce any JSON value by traversing depth first and visiting each node

Example: calculate the sum of all number values in a json object

import {reduce} from 'json-reduce'

const document = {
  first: 1,
  second: 2,
  deep: {
    array: [3, 4, 5, 6],
    seven: 7

const result = reduce(
  (acc, value, path) => (typeof value === 'number' ? acc + value : acc),

//=> 28


reduce(value, reducer, initialValue)

`reducer` is the reducer function to execute for each node in the tree, and is given three arguments:

  - `accumulator` - The accumulation of the callback's return values; it is the value returned
  from the previous invocation of the callback, or `initialValue`.
  - `value` - The current node being traversed
  - `path` - The "dot-path" to the current node being traversed, e.g. `['deep', 'array', 2]`

## Skipping subtrees
Sometimes when encountering a specific object or array value, you want to skip traversing the subtree. This can be done calling
a provided SKIP function like this:

import reduce, {SKIP} from 'json-reduce'

const doc = {
  species: [
    {name: 'clover', type: 'plant'},
    {name: 'trout', type: 'fish', eats: [{type: 'animal', name: 'crayfish'}]},
      type: 'animal',
      name: 'bear',
      food: [
          type: 'animal',
          name: 'deer',
          food: [{type: 'plant', name: 'leaves'}]
          type: 'plant',
          name: 'blueberry'

const result = reduce(
  (acc, val, path) => {
    if (val.type === 'plant' || val.type === 'fish') {
      // We don't want to traverse the subtrees of these
      return SKIP
    // Collect all traversed paths
    return acc.concat([path])
  ['species', 2],
  ['species', 2, 'type'],
  ['species', 2, 'name'],
  ['species', 2, 'food'],
  ['species', 2, 'food', 0],
  ['species', 2, 'food', 0, 'type'],
  ['species', 2, 'food', 0, 'name'],
  ['species', 2, 'food', 0, 'food']

Return and skip

In addition to return SKIP, you can also call SKIP with a return value for convenience, to both return the accumulated value and signal subtree skipping in one operation, e.g.:
reduce(doc, (acc, node) => {
  if (node.type === 'plant' || node.type === 'fish') {
    // Uppercase plant and fish names, but skip traversing subtrees
    return SKIP(
        name: node.name.toUpperCase()
  return acc
}, [])

Gotchas / Limitations

  • Initial value is required. json-reduce does not work like Array.prototype.reduce with respect to missing initial value
  • No circular reference detection and handling. Passing a circular structure to reduce() will probably crash with maximum call stack size exceeded.
  • Assumes a data structure that consists of valid JSON data types only. Traversal of Map, Set, etc. are not currently supported (PR welcome!).