R Academy · leksjon

Håndtere nestede JSON-strukturer

Flat ut dypt nestet JSON til ryddige datarammer for analyse.

Leksjon 4 av 413 trinn

Håndtere nestede JSON-strukturer er en gratis leksjon i R Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i R Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i R Academy inneholder totalt 4 leksjoner.

Hvorfor nøstet JSON er krevende

REST-API-er returnerer ofte dypt nøstet JSON, der ett enkelt felt kan inneholde en array med objekter som igjen inneholder flere objekter. For å flate ut denne strukturen til en ryddig data-ramme må du forstå hvordan jsonlite, purrr og tidyr fungerer sammen.

# Example nested JSON from a REST API:
json_str <- '{
  "user": {
    "id": 1,
    "name": "Alice",
    "orders": [
      {"order_id": 101, "total": 59.99, "status": "shipped"},
      {"order_id": 102, "total": 24.50, "status": "pending"}
    ]
  }
}'

# The challenge: 'orders' is an array of objects inside 'user'
cat('Nested JSON loaded as string, length:', nchar(json_str))

fromJSON() — Grunnleggende tolking

jsonlite::fromJSON() konverterer en JSON-streng eller filbane til R-objekter. Enkel, flat JSON blir en liste eller data-ramme. Nøstet JSON blir en nøstet liste — arrayer med objekter blir data-rammer lagret i listekolonner.

library(jsonlite)

# Parse flat JSON
flat_json <- '{"name": "Alice", "age": 30, "score": 95.5}'
result <- fromJSON(flat_json)
cat('Name:', result$name, '\n')
cat('Age: ', result$age,  '\n')

# Parse an array of objects — becomes a data frame
array_json <- '[{"id":1,"val":10},{"id":2,"val":20},{"id":3,"val":30}]'
df <- fromJSON(array_json)
cat('Class:', class(df), '\n')
print(df)

fromJSON() med flatten = TRUE

Argumentet flatten = TRUE ber fromJSON() om å pakke ut nøstede data-rammer rekursivt til kolonner med navn adskilt av punktum. Dette fungerer godt for ett nivå med nøsting og er den raskeste måten å håndtere moderat nøstet JSON på.

library(jsonlite)

json_str <- '[{
  "id": 1,
  "name": "Alice",
  "address": {"city": "Berlin", "country": "Germany"}
},{
  "id": 2,
  "name": "Bob",
  "address": {"city": "Paris", "country": "France"}
}]'

# Without flatten:
nested_df <- fromJSON(json_str, flatten = FALSE)
cat('address class:', class(nested_df$address), '\n')

# With flatten = TRUE:
flat_df <- fromJSON(json_str, flatten = TRUE)
cat('Columns:', names(flat_df), '\n')
print(flat_df)

Nøstede arrayer blir listekolonner

Når et JSON-felt inneholder en array med objekter, lagrer fromJSON() det som en listekolonne i data-rammen — hver celle inneholder en data-ramme. Du må hente ut eller pakke ut disse eksplisitt.

library(jsonlite)

json_str <- '[{
  "user_id": 1,
  "tags": ["R", "Python", "SQL"]
},{
  "user_id": 2,
  "tags": ["Java", "Kotlin"]
}]'

df <- fromJSON(json_str)
cat('tags column class:', class(df$tags), '\n')

# Access tags for user 1:
cat('User 1 tags:', df$tags[[1]], '\n')
cat('User 2 tags:', df$tags[[2]])

purrr::map() — Hente ut nøstede felt

purrr::map() bruker en funksjon på hvert element i en liste. Når hvert element er en navngitt liste (et tolket JSON-objekt), kan du sende inn en streng for å hente ut et navngitt felt fra hvert element — en kortfattet erstatning for en løkke.

library(jsonlite)
library(purrr)

json_str <- '[{
  "id": 1,
  "meta": {"score": 88, "grade": "B"}
},{
  "id": 2,
  "meta": {"score": 95, "grade": "A"}
},{
  "id": 3,
  "meta": {"score": 72, "grade": "C"}
}]'

records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# Extract 'score' from each record's 'meta' object
scores <- map_dbl(records, function(r) r$meta$score)
grades <- map_chr(records, function(r) r$meta$grade)

cat('Scores:', scores, '\n')
cat('Grades:', grades)

purrr::map() med snarvei for strenger

purrr::map(list, 'field_name') er en kortform for å hente ut et navngitt felt fra hvert element — tilsvarende map(list, function(x) x[['field_name']]). Bruk map_chr(), map_dbl() og så videre for å få typede atomære vektorer i stedet for lister.

library(jsonlite)
library(purrr)

json_str <- '[{"name":"Alice","score":90},{"name":"Bob","score":78},{"name":"Carol","score":85}]'

# Parse as list of lists
records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# String shortcut to extract field
names_vec  <- map_chr(records, 'name')
scores_vec <- map_dbl(records, 'score')

cat('Names: ', names_vec, '\n')
cat('Scores:', scores_vec, '\n')

# Build a clean data frame
clean_df <- data.frame(name = names_vec, score = scores_vec)
print(clean_df)

Dyp nøsting med map()-kjeder

For dypt nøstet JSON kjeder du sammen flere kall til map(). Hvert kall går ett nivå ned. Bruk map(list, 'field') på hvert nivå, og bruk en typet map_*() på det innerste nivået for å hente ut den endelige verdien.

library(jsonlite)
library(purrr)

json_str <- '[{
  "id": 1,
  "company": {"hq": {"city": "Berlin", "country": "Germany"}}
},{
  "id": 2,
  "company": {"hq": {"city": "Tokyo",  "country": "Japan"}}
}]'

records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# Navigate: records -> company -> hq -> city
cities <- map_chr(records, function(r) r$company$hq$city)
cat('Cities:', cities, '\n')

# Or using nested map shortcut:
ids <- map_int(records, 'id')
cat('IDs:', ids)

tidyr::unnest() — Flate ut listekolonner

tidyr::unnest() utvider en listekolonne som inneholder data-rammer, og oppretter én rad per nøstet element. Dette er den standardiserte tidy-metoden for å flate ut én-til-mange-relasjoner i JSON-data.

library(jsonlite)
library(tidyr)
library(dplyr)

json_str <- '[{
  "user_id": 1,
  "orders": [{"oid":101,"total":50},{"oid":102,"total":30}]
},{
  "user_id": 2,
  "orders": [{"oid":103,"total":80}]
}]'

df <- fromJSON(json_str)
cat('Before unnest, rows:', nrow(df), '\n')
cat('orders class:', class(df$orders), '\n')

# Unnest expands one row per order
expanded <- unnest(df, cols = orders)
cat('After unnest, rows:', nrow(expanded), '\n')
print(expanded)

jsonlite::flatten() på data-rammer

jsonlite::flatten() fungerer på en data-ramme som allerede er tolket (ikke en JSON-streng), og utvider rekursivt alle nøstede kolonner med data-rammer til navngitte kolonner med punktum. Dette er nyttig etter fromJSON(..., flatten = FALSE) når du vil flate ut dataene som et etterbehandlingstrinn.

library(jsonlite)

json_str <- '[{
  "id": 1,
  "profile": {"age": 25, "city": "Rome"}
},{
  "id": 2,
  "profile": {"age": 31, "city": "Oslo"}
}]'

# Parse without auto-flatten
nested <- fromJSON(json_str, flatten = FALSE)
cat('Columns before flatten:', names(nested), '\n')
cat('profile class:', class(nested$profile), '\n')

# Apply flatten() post-hoc
flat <- flatten(nested)
cat('Columns after flatten:', names(flat), '\n')
print(flat)

Håndtere nullverdier i nøstet JSON

JSON-verdier med null tolkes som NULL i R, noe som skaper problemer når du bygger data-rammer — en NULL i en liste fjerner elementet helt. Bruk purrr::map() med argumentet .default eller %||% for å erstatte manglende verdier på en trygg måte.

library(jsonlite)
library(purrr)

json_str <- '[{"id":1,"email":"alice@example.com"},{"id":2,"email":null},{"id":3,"email":"carol@example.com"}]'

records <- fromJSON(json_str, simplifyDataFrame = FALSE)

# Unsafe: NULL drops the element
# emails <- map_chr(records, 'email')  # ERROR on null

# Safe: provide a default for missing values
emails <- map_chr(records, function(r) {
  if (is.null(r$email)) NA_character_ else r$email
})

cat('Emails:', emails)
cat('NAs:', sum(is.na(emails)))

Komplett pipeline: API-JSON til ryddig data-ramme

Her settes alt sammen: en realistisk pipeline som tolker nøstet JSON fra et API, henter ut felt med purrr, håndterer nullverdier og produserer en ryddig data-ramme som er klar for analyse.

library(jsonlite)
library(purrr)
library(dplyr)

# Simulated API response
api_json <- '[{
  "id": 1, "name": "Alice",
  "stats": {"score": 92, "rank": 1}
},{
  "id": 2, "name": "Bob",
  "stats": null
},{
  "id": 3, "name": "Carol",
  "stats": {"score": 85, "rank": 3}
}]'

records <- fromJSON(api_json, simplifyDataFrame = FALSE)

result <- tibble(
  id    = map_int(records,  'id'),
  name  = map_chr(records,  'name'),
  score = map_dbl(records,  function(r) if (is.null(r$stats)) NA_real_ else r$stats$score),
  rank  = map_int(records,  function(r) if (is.null(r$stats)) NA_integer_ else r$stats$rank)
)

print(result)

Sjekk deg selv

Du har en data-ramme df der kolonnen orders er en listekolonne som inneholder data-rammer (én per bruker). Hvilken funksjon utvider denne til én rad per ordre?

Nestet JSON – viktigste punkter

Håndtering av nestet JSON i R krever et verktøysett i flere lag:

  • fromJSON(json, flatten = TRUE) – flater automatisk ut ett nivå av nestingen
  • fromJSON(json, simplifyDataFrame = FALSE) – gir en liste med lister for manuell behandling
  • Nestede matriser → listekolonner i den resulterende dataframen
  • purrr::map_chr/dbl/int(list, 'field') – henter ut verdier med riktig type fra hvert element
  • Kjedede map()-kall går gjennom dype nestingsnivåer
  • tidyr::unnest(df, cols = col) – utvider listekolonner med dataframes
  • jsonlite::flatten(df) – flater ut nestede dataframe-kolonner etter parsing
  • Kontroller alltid for NULL med if (is.null(x)) NA else x
library(jsonlite)
library(purrr)

# Quick reference:
json <- '[{"id":1,"info":{"val":10}},{"id":2,"info":null}]'
recs <- fromJSON(json, simplifyDataFrame = FALSE)

# Safe extraction with null guard
vals <- map_dbl(recs, function(r) {
  if (is.null(r$info)) NA_real_ else r$info$val
})

result <- data.frame(id = map_int(recs, 'id'), val = vals)
print(result)
Gratis å komme i gang

Lær deg R med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
43
Leksjoner
159

Ofte stilte spørsmål

Er leksjonen «Håndtere nestede JSON-strukturer» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien R Academy, inkludert «Håndtere nestede JSON-strukturer», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i R Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Håndtere nestede JSON-strukturer»?

Flat ut dypt nestet JSON til ryddige datarammer for analyse. Du øver på R Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med R Academy?

Ingen tidligere erfaring er nødvendig. R Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «Håndtere nestede JSON-strukturer»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne R Academy-leksjonen?

Ja. Alle R Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Tolke JSON med jsonlite
  2. Sende HTTP-forespørsler med httr2
  3. Bruke REST-API-er i R
  4. Håndtere nestede JSON-strukturer
← Tilbake til R Academy