Iterating through JSON Dictionary

Hey All! First off you all have been great helping me understand APIs and JSON. I really appreciate your help.

I am at my next and hopefully last impasse.

I have data coming through my GET. I have defined the dictionaries and the “data” dictionary is what houses multiple values. Here is a sample of the GET results

{
    "success":true,
    "data": [{
        "id":18570,
        "username":"USER1",
        "avatar":"/user/avatar/18570_1649260068.jpg",
        "groups":[101,102,103,104]
    },{
        "id":38685,
        "username":"USER2",
        "avatar":"/assets/images/default.png",
        "groups":[]
    }]
}

Here is the my code

dim url As String = "https://api.APICOMPANY.COM/api/v1/users/search?username=" + user1.Text + "&categoryId=1"
response.Text = url
dim socket1 As New URLConnection
socket1.RequestHeader("x-user-jwt") = app.JWT
Var data As String = socket1.SendSync("GET", url, 20)

Var jData As Dictionary = ParseJSON(data)
Var dict As Dictionary = jData.Value("data")

For Each entry As DictionaryEntry In dict
  'userID1 = dict.Value("id")
  response.Text = entry.Value
Next

Eventually I will pass this info to a ListBox and populate all relevant columns. In the meantime I am just trying to get it to return one value. I realize my Each will overwrite the text field with each pass that is fine. Because as it stands I am getting nothing.

Do you get an error here? Data is an array. I have seen in the docs that the examples use:

var jsonArray() as variant = jData.Value("data")

What value do you want? “id”, “username”, “avatar”. Maybe use a TextArea and AddText?

2 Likes

Keep working with JSONItems and forget the Array/Dictionary internal switch.

2 Likes

The topic should be “Iterating through JSON contents”

Var jsonOrigin As String = "{""success"":true,""data"":[{""id"":18570,""username"":""USER1"",""avatar"":""/user/avatar/18570_1649260068.jpg"",""groups"":[101,102,103,104]},{""id"":38685,""username"":""USER2"",""avatar"":""/assets/images/default.png"",""groups"":[]}]}"

Var json As New JSONItem(jsonOrigin)
Var jsonData As JSONItem = json.Value("data")

For i As Integer = 0 to jsonData.Count - 1
  Var item As JSONItem = jsonData.ValueAt(i) // one user
  Var uId As Integer = item.Value("id")
  System.DebugLog uId.ToString + " data = " + item.ToString
Next

// Check de debug console output ("Messages" bottom tab)
2 Likes

This is fine but what happens when I need to get in to an array for an item?

Expanding on Rick’s answer, to iterate over the “groups” attribute of a user, you could do something like this.

Var jsonOrigin As String = "{""success"":true,""data"":[{""id"":18570,""username"":""USER1"",""avatar"":""/user/avatar/18570_1649260068.jpg"",""groups"":[101,102,103,104]},{""id"":38685,""username"":""USER2"",""avatar"":""/assets/images/default.png"",""groups"":[]}]}"

Var json As New JSONItem(jsonOrigin)
Var jsonData As JSONItem = json.Value("data")

For i As Integer = 0 to jsonData.Count - 1
  
  Var item As JSONItem = jsonData.ValueAt(i) // one user
  Var uId As Integer = item.Value("id")
  System.DebugLog uId.ToString + " data = " + item.ToString
  
  Var groups AS JSONItem = item.Value("groups")
  
  For x As Integer = 0 to groups.Count - 1
    Var group As Integer = groups.ValueAt(x)
    System.DebugLog group.ToString
  Next
  
Next
1 Like

To clarify that, the JSONItem class can behave as both an object and as an array. In fact, there is an IsArray method on it to tell you which is which.

If it’s an array use childAt(index) and ValueAt(index) too get the array items. If not, use Child(name) and Value(name) to get properties.

BTW, The reason there are two of each of these is for code completion. Child and ChildAt return JSONItems so if you know the structure you of the JSON you have, you could easily do something like this:

Dim js as JSONItem = root.ChildAt("pages").Child("name")
2 Likes

Yes. You need to walk the tree to the item of interest and retrieve its contents

E.g.

root.Child("thearray").ValueAt(2)  // the 3rd item there

Greg’s example contains a small lapse, ChildAt() takes an index, not a key as Child()

2 Likes

Awesome! This worked perfect.