Getting Data from JSON

Getting Data from JSON
0

#1

I have JSON data and I am having trouble accessing it correctly. The data is structured as shown below:

const myJSON = {
  "users" : {
    "somerandomusername" : {
      "actions" : {
      }
      "username" : "A name"
    },
   "somerandomusername2" : {
      "actions" : {
      "username" : "Another name"
      }
   }
  }
}

I want to be able to loop through all of the users, even though I don’t know what the usernames will be. So, I’d like to use a for loop something like this:

for (let i = 0; i < myJSON.users.length; i++) {
  console.log(myJSON.users[i]); // should log 'somerandomusername' and on second run should log 'somerandomusername2'
  console.log(myJSON.users[i].actions); // should log all actions under 'somerandomusername' and on second run should log all actions under 'somerandomusername2'
  console.log(myJSON.users[i].username); // should log 'A name' and on second run should log 'Another name'
}

Is it possible to do this? I keep getting ‘undefined’ for my console logs

Thanks!


#2

myJSON.users is an object, not an array. You can’t iterate through objects just using for loops like this. If you want to iterate through it, just change the brackets surrounding your user objects.

const myJSON = {
  "users" : [ // < change to an array 
    "somerandomusername" : {
      "actions" : {
      }
      "username" : "A name"
    },
   "somerandomusername2" : {
      "actions" : {
      "username" : "Another name"
      }
   }
  ]
}

#3

Thanks for the response!

When I make the change you suggest, I get an error stating that an unexpected token ‘:’ was found.


#4

My question is “somerandomusername” supposed to contain an object with two properties (“actions” and “username”)? Or, is it suppose to contain an object with an “actions” property which contains a property named “username” like in the “somerandomusername2” property?


#5

somerandomusername should contain an object that has two properties, ‘actions’ and ‘username’. Inside of ‘actions’ will be a bunch of actions that the learner took while interacting with an online course I created. Ultimately, I just want to be able to sort by username and list out all of the actions that they took. I’m new to storing data in a database so it is entirely possible that I set this up incorrectly from the beginning.

For what its worth, ‘somerandomusername’ is actually an anonymous userId assigned by Firebase when a user visits the course.

I messed up somerandomusername2, sorry!


#6

To get back to iterating through objects, it is possible with the right type of for loop. (I made a small adjustment to myJSON to make it a valid object.)

const myJSON = {
  "users" : {
    "somerandomusername" : {
      "actions" : {
      },
      "username" : "A name"
    },
    "somerandomusername2" : {
      "actions" : {
        "username" : "Another name"
      }
    }
  }
}

for (var user in myJSON.users) {
  console.log('Data for user',user, 'is:', myJSON.users[user])
}

#7

There’s a couple of missing commas, unnecessary property names, and a missing curly brace.

const myJSON = {
  "users" : [  
    { // << remove property names
      "actions" : {}, //<< add comma, remove newline
      "username" : "A name"
    },
   {
      "actions" : {}, // << add curly brace and comma
      "username" : "Another name"
   }
  ]
}

#8

If you meant myJSON to look like:

const myJSON = {
  "users" : {
    "somerandomusername" : {
      "actions" : { },
      "username" : "A name"
    },
    "somerandomusername2" : {
      "actions" : { },
      "username" : "Another name"
    }
  }
};

then you could write:

const userKeys = Object.keys(myJSON.users);
for (let i=0; i < userKeys.length; i++) {
  console.log(userKeys[i]); // displays "somerandomusername" in first iteration and "somerandomusername2" in second iteration
  console.log(myJSON.users[userKeys[i]].actions); // displays the object actions but it is currently empty.  If you want to display all of the actions, you would need to loop through the "action" object keys 
  console.log(myJSON.users[userKeys[i]].username); // displays "A name" in first iteration and "Another name" in second iteration
}

#9

Thank you for your help! This is working for me! I really appreciate it.


#10

The for loop you have is the most basic, generic for loop:

for (let i = 0; i < myJSON.users.length; i++) {
  console.log(i)
}

It can be used for arrays and objects. Above you have it for an array, but like @PortableStick mentioned, you don’t have an array. If you want to use this generic for loop on an object, you would have to change the condition to work with an object like this using the keys property:

for (let i = 0; i < Object.keys(myJSON.users); i++) {
  console.log(i)
}

There are also for…of loops which are used for arrays

for (let index of array) {
  // do something
}

There also for…in loops like @kevinSmith mentioned:

for (let property in object) {
  // do something
}

So, the problem was that you were mistaking an object as an array. In the big picture, however, realize that there are many different ways to accomplish this using a wide variety of for loop types. I personally think Kevin’s solution is the most clear and straightforward.


#11

I feel the need to mention that when you have something like a list of users, an array is the right choice. Trying to generate a list of users as properties in an object is asking for a lot of pain, and if you plan to move this to a database then there’s no chance it’s going to return you just an object. Here are some questions that come to mind when I think about this design:

  • How do you generate the “randomUsername” when adding a new user?
  • How do you avoid hash collisions?
  • How are you going to sort this collection, and how long will that take?
  • How can you efficiently search through your users to find one particular person?
  • How will you keep track of the number of users in your collection?
  • If you need your users to be in a particular order, how will you enforce this when using an object?

Arrays solve all of these problems.

myJSON.users.push(newUser);
myJSON.users.sort(/** sort function**/)
myJSON.users.length

This may seem like making a mountain out of an anthill, but I think this is instructional. Being able to choose the right data structure is something that will make you stand out as a self-taught programmer. Perhaps you’ve got a great reason for storing users as object values - great! But imagine you’re at an interview and this project comes up. Your interviewer looks through your code, sees that you store your collection in an object and asks you, “Why did you choose to do this?”. If you’ve got a good, solid answer, then there’s no problem. If your response is to shrug and say, “I don’t know”, then you’re probably not going to get that job.


#12

Thank you so much for taking the time to write this out. Honestly, I have never done anything like this before so I am just trying to following the docs in Firebase. I am definitely open to doing this a different/better way, I’m just not sure how.

Basically, I generate the random username when the course is launched using the anonymous authentication feature on Firebase. Throughout the course, the learner can complete a variety of interactions and each time he/she completes an action, I want the action and the time the action occurred to register in the database.

So, ideally, what I want is a structure something like:

user

  • action
    • time action occurred

So far, I haven’t been able to figure out how to use the Firebase database to do something like that. I am still learning though and I’m sure it is possible.

Thanks again for your time and direction, I appreciate it.


#13

What kind of actions will your users be performing which you want to record?


#14

I build online learning courses, so some examples of actions could be:

  • Started the course
  • Finished the course
  • Clicked on a ‘Learn More’ button
  • Launched a PDF
  • Clicked a ‘Policy’ link
  • Played a video
  • Answered an assessment question

Things like that.


#15

Got it. I was thinking you were wanting to log updates to the database, where database triggers would be applicable. Instead, you are defining your own set of actions.


#16

Yes, exactly. The idea being that I can easily run reports that show things like:

  • x% of users will launch a policy link if we provide it
  • x% of users viewed a specific page
  • length of time it takes to complete the course on average
  • etc

#17

Gotcha! I assume that you’ve already looked at this page, then:

https://firebase.google.com/docs/database/web/structure-data

because it gives an example that’s very close to what you had at in your original post:

{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      "contacts": { "ghopper": true },
    },
    "ghopper": { ... },
    "eclarke": { ... }
  }
}

It also says that [a]ll Firebase Realtime Database data is stored as JSON objects. So, I was wrong to say there’s no chance that you’d get data from a database like this since, obviously, data does come from at least one database like this. Thankfully, all of the questions I had earlier are addressed by the Firebase API. It will handle hashing as you just push new data to the DB, and it can sort by any key you have in your data. So, as long as you let their servers handle the hard work, you shouldn’t have any problem with this.


#18

your question same as me.when I start coding for several days.I think ,you might learn some data structure.such as Array,Object.and how to loop the Array and the member of Object.And then.you can easily solve these problems.
I hope this can help you.come on !!!:hugs: