Iterate through an object which has nested objects in nodeJs

12,706

Solution 1

Relatively simple recursion problem, I would use a function that calls itself when sub objects are found. I would also avoid using a for in loop, and instead use a forEach on the object's keys (it's much faster, and doesn't require a hasOwnProperty check.)

function resetValuesToZero (obj) {
    Object.keys(obj).forEach(function (key) {
        if (typeof obj[key] === 'object') {
            return resetValuesToZero(obj[key]);
        }
        obj[key] = 0;
    });
}

var stats = {
     bookServed: {
         redis: 90,
         s3: 90,
         signedUrl: 70
     },
     errors: {
         redis: {
             bookService: 70,
             mapi: 50,
             capi: 30
         },
         AWS: {
             signedUrl: 70,
             downloadBook: 50,
             searchBook: 10
         },
         decryption: 60
     }
 };

console.log(stats.errors.AWS.signedUrl); // 70
resetValuesToZero(stats);
console.log(stats.errors.AWS.signedUrl); // 0

Solution 2

The below solution uses object-scan, which uses an iterative implementation to traverse the input. Also note that this will traverse into any array structures similar to the accepted answer.

// const objectScan = require('object-scan');

const rewriter = objectScan(['**'], {
  rtn: 'count',
  filterFn: ({ value, parent, property }) => {
    if (typeof value === 'number') {
      parent[property] = 0;
      return true;
    }
    return false;
  }
});

const stats = { bookServed: { redis: 90, s3: 90, signedUrl: 70 }, errors: { redis: { bookService: 70, mapi: 50, capi: 30 }, AWS: { signedUrl: 70, downloadBook: 50, searchBook: 10 }, decryption: 60 } };

console.log(rewriter(stats)); // returns count of replaces
// => 10

console.log(stats);
/* =>
{ bookServed: { redis: 0, s3: 0, signedUrl: 0 },
  errors:
  { redis: { bookService: 0, mapi: 0, capi: 0 },
    AWS: { signedUrl: 0, downloadBook: 0, searchBook: 0 },
    decryption: 0 } }
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Share:
12,706
Amaynut
Author by

Amaynut

Updated on July 14, 2022

Comments

  • Amaynut
    Amaynut almost 2 years

    I have a javascript object with multiple nested objects like this :

     var stats = {
         bookServed: {
             redis: 90,
             s3: 90,
             signedUrl: 70
         },
         errors: {
             redis: {
                 bookService: 70,
                 mapi: 50,
                 capi: 30
             },
             AWS: {
                 signedUrl: 70,
                 downloadBook: 50,
                 searchBook: 10
             },
             decryption: 60
         }
     };
    

    What would be the cleanest way to iterate through all its properties and set each value to 0 for instance. I wrote something like this

     for (var property in stats) {
         if (stats.hasOwnProperty(property)) {
             if (typeof property === "object") {
                 for (var sub_property in property)
                     if (property.hasOwnProperty(sub_property)) {
                         sub_property = 0
                     }
             } else {
                 property = 0;
             }
         }
     }
    

    I'm willing to use a library like underscore.js to do the task properly.

  • Kevin B
    Kevin B over 8 years
    Note that if the object is extremely deeply nested, this could throw a stack overflow exception, but I'd consider that to be very much an edge case. To overcome that, you would need to make this function asynchronous, but I wouldn't bother with that unless you actually ran into that problem, as it definitely complicates things a bit.
  • vincent
    vincent over 3 years
    Posted an answer that uses the iterative approach rather than recursion. Also not that this answer will traverse into arrays (it is not clear from the question if that is intended).