61

I have a JSON file which I need to iterate over, as shown below...

{
    "device_id": "8020",
    "data": [{
        "Timestamp": "04-29-11 05:22:39 pm",
        "Start_Value":  0.02,
        "Abstract": 18.60,
        "Editor": 65.20
    }, {
        "Timestamp": "04-29-11 04:22:39 pm",
        "End_Value":  22.22,
        "Text": 8.65,
        "Common": 1.10,
        "Editable": "true",
        "Insert": 6.0
    }]
}

The keys in data will not always be the same (i've just used examples, there are 20 different keys), and as such, I cannot set up my script to statically reference them to get the values.

Otherwise I could state

var value1 = json.data.Timestamp;
var value2 = json.data.Start_Value;
var value3 = json.data.Abstract;
etc

In the past i've used a simple foreach loop on the data node...

foreach ($json->data as $key => $val) {
    switch($key) {
        case 'Timestamp':
            //do this;
        case: 'Start_Value':
            //do this
    }
}

But don't want to block the script. Any ideas?

crawf
  • 9,448
  • 10
  • 33
  • 43

9 Answers9

104

You can iterate through JavaScript objects this way:

for(var attributename in myobject){
    console.log(attributename+": "+myobject[attributename]);
}

myobject could be your json.data

Van Coding
  • 24,244
  • 24
  • 88
  • 132
25

I would recommend taking advantage of the fact that nodeJS will always be ES5. Remember this isn't the browser folks you can depend on the language's implementation on being stable. That said I would recommend against ever using a for-in loop in nodeJS, unless you really want to do deep recursion up the prototype chain. For simple, traditional looping I would recommend making good use of Object.keys method, in ES5. If you view the following JSPerf test, especially if you use Chrome (since it has the same engine as nodeJS), you will get a rough idea of how much more performant using this method is than using a for-in loop (roughly 10 times faster). Here's a sample of the code:

 var keys = Object.keys( obj );
 for( var i = 0,length = keys.length; i < length; i++ ) {
     obj[ keys[ i ] ];
 }
Nathan Sweet
  • 422
  • 5
  • 8
  • 1
    I prefer the Object.keys approach as well... A small improvement to your suggestion, but if you do a reverse for loop it's a bit faster. Of course only applies if order of iteration doesn't matter! Although since there's technically no guaranteed ordering to the order in which object keys are returned it may be a mute point that order would ever matter ;) http://jsperf.com/forward-vs-reverse-for-loop [code] var keys = Object.keys(obj); for (i = keys.length; i--;) { obj[keys[i]]; } [/code] – Austin Floyd Jul 27 '14 at 22:22
  • Better to use let rather than var: for( let i = 0; length = keys.length; i < length; i++) – Seth Eden Jan 04 '21 at 17:32
24

You may also want to use hasOwnProperty in the loop.

for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) {
        switch (prop) {
            // obj[prop] has the value
        }
    }
}

node.js is single-threaded which means your script will block whether you want it or not. Remember that V8 (Google's Javascript engine that node.js uses) compiles Javascript into machine code which means that most basic operations are really fast and looping through an object with 100 keys would probably take a couple of nanoseconds?

However, if you do a lot more inside the loop and you don't want it to block right now, you could do something like this

switch (prop) {
    case 'Timestamp':
        setTimeout(function() { ... }, 5);
        break;
    case 'Start_Value':
        setTimeout(function() { ... }, 10);
        break;
}

If your loop is doing some very CPU intensive work, you will need to spawn a child process to do that work or use web workers.

mak
  • 13,267
  • 5
  • 41
  • 47
  • hasOwnProperty seems interesting, i might incorporate that into the loop. Work inside the loop isnt that intensive. Just adding the values given to a database. All thats required is a bit of formatting for the SQL. – crawf Apr 30 '11 at 11:39
6

My most preferred way is,

var objectKeysArray = Object.keys(yourJsonObj)
objectKeysArray.forEach(function(objKey) {
    var objValue = yourJsonObj[objKey]
})
Tharanga
  • 2,689
  • 1
  • 21
  • 18
  • 1
    Thanks for your help, I know the question is old but I have many hours looking for solutions and yours has been good for me only that to work well I added the property to var objValue = yourJsonObj [objKey] .properties @Tharanga – DanyMartinez_ Mar 19 '21 at 01:27
6

If you want to avoid blocking, which is only necessary for very large loops, then wrap the contents of your loop in a function called like this: process.nextTick(function(){<contents of loop>}), which will defer execution until the next tick, giving an opportunity for pending calls from other asynchronous functions to be processed.

Mike Scott
  • 4,719
  • 2
  • 21
  • 12
4

If we are using nodeJS, we should definitely take advantage of different libraries it provides. Inbuilt functions like each(), map(), reduce() and many more from underscoreJS reduces our efforts. Here's a sample

    var _=require("underscore");
    var fs=require("fs");

    var jsonObject=JSON.parse(fs.readFileSync('YourJson.json', 'utf8'));


    _.map( jsonObject, function(content) {
        _.map(content,function(data){
           if(data.Timestamp)
              console.log(data.Timestamp)          
           })
      })
Nish
  • 695
  • 1
  • 7
  • 14
3

A little late but I believe some further clarification is given below.

You can iterate through a JSON array with a simple loop as well, like:

for(var i = 0; i < jsonArray.length; i++)
{
    console.log(jsonArray[i].attributename);
}

If you have a JSON object and you want to loop through all of its inner objects, then you first need to get all the keys in an array and loop through the keys to retrieve objects using the key names, like:

var keys = Object.keys(jsonObject);
for(var i = 0; i < keys.length; i++) 
{
    var key = keys[i];
    console.log(jsonObject.key.attributename);
}
Andreas
  • 5,393
  • 9
  • 44
  • 53
Asad Ali Choudhry
  • 4,985
  • 4
  • 31
  • 36
2

Not sure if it helps, but it looks like there might be a library for async iteration in node hosted here:

https://github.com/caolan/async

Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript. Although originally designed for use with node.js, it can also be used directly in the browser.

Async provides around 20 functions that include the usual 'functional' suspects (map, reduce, filter, forEach…) as well as some common patterns for asynchronous control flow (parallel, series, waterfall…). All these functions assume you follow the node.js convention of providing a single callback as the last argument of your async function.

JWally
  • 582
  • 11
  • 18
1

Take a look at Traverse. It will recursively walk an object tree for you and at every node you have a number of different objects you can access - key of current node, value of current node, parent of current node, full key path of current node, etc. https://github.com/substack/js-traverse. I've used it to good effect on objects that I wanted to scrub circular references to and when I need to do a deep clone while transforming various data bits. Here's some code pulled form their samples to give you a flavor of what it can do.

var id = 54;
var callbacks = {};
var obj = { moo : function () {}, foo : [2,3,4, function () {}] };

var scrubbed = traverse(obj).map(function (x) {
    if (typeof x === 'function') {
        callbacks[id] = { id : id, f : x, path : this.path };
        this.update('[Function]');
        id++;
    }
});

console.dir(scrubbed);
console.dir(callbacks);
AlexGad
  • 6,612
  • 5
  • 33
  • 45