Hantera nästlade JSON-strukturer
Platta ut djupt nästad JSON till tidy data frames för analys.
Hantera nästlade JSON-strukturer är en gratis lektion i R Academy på CoddyKit. Detta är lektion 4 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för R Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i R Academy innehåller totalt 4 lektioner.
Varför nästlad JSON är svårhanterlig
REST-API:er returnerar ofta djupt nästlad JSON där ett enskilt fält kan innehålla en array med objekt, som i sin tur innehåller fler objekt. För att platta ut denna struktur till en tidy data frame behöver man förstå hur jsonlite, purrr och tidyr samverkar.
# 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() — Grundläggande tolkning
jsonlite::fromJSON() konverterar en JSON-sträng eller filsökväg till R-objekt. Enkel platt JSON blir en lista eller data frame. Nästlad JSON blir en nästlad lista — arrayer med objekt blir data frames som lagras i listkolumner.
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 instruerar fromJSON() att rekursivt packa upp nästlade data frames till kolumner med punktseparerade namn. Detta fungerar bra för en nästlingsnivå och är det snabbaste sättet att hantera måttligt nästlad JSON.
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ästlade arrayer blir listkolumner
När ett JSON-fält innehåller en array med objekt lagrar fromJSON() den som en listkolumn i data framen — varje cell innehåller en data frame. Dessa måste nås eller packas upp uttryckligen.
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() — Extrahera nästlade fält
purrr::map() tillämpar en funktion på varje element i en lista. När varje element är en namngiven lista, alltså ett tolkat JSON-objekt, kan en sträng skickas in för att extrahera ett namngivet fält från varje element — ett kortfattat alternativ till en loop.
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 strängförkortning
purrr::map(list, 'field_name') är en kortform för att extrahera ett namngivet fält från varje element — motsvarande map(list, function(x) x[['field_name']]). Använd map_chr(), map_dbl() och så vidare för att få typade atomära vektorer i stället för listor.
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)Djup nästling med kedjor av map()
För djupt nästlad JSON kedjar man flera anrop till map(). Varje anrop går ner en nivå. Använd map(list, 'field') på varje nivå och tillämpa ett typat map_*() på den innersta nivån för att extrahera det slutliga värdet.
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() — Platta ut listkolumner
tidyr::unnest() expanderar en listkolumn som innehåller data frames och skapar en rad för varje nästlat element. Detta är tidy-standardmetoden för att platta ut en-till-många-relationer 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 frames
jsonlite::flatten() fungerar på en redan tolkad data frame, inte på en JSON-sträng, och expanderar rekursivt alla nästlade kolumner med data frames till kolumner med punktseparerade namn. Det är användbart efter fromJSON(..., flatten = FALSE) när man vill platta ut datan som ett efterbearbetningssteg.
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)Hantera null-värden i nästlad JSON
JSON-värdet null tolkas som NULL i R, vilket orsakar problem när data frames byggs — ett NULL i en lista tar bort elementet helt. Använd purrr::map() med argumentet .default eller %||% för att ersätta saknade värden på ett säkert sätt.
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)))Fullständig pipeline: från API-JSON till tidy data frame
Här sätts allt ihop: en realistisk pipeline som tolkar nästlad JSON från ett API, extraherar fält med purrr, hanterar null-värden och skapar en tidy data frame som är klar för analys.
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)Snabbtest
Ni har en data frame df där kolumnen orders är en listkolumn som innehåller data frames, en per användare. Vilken funktion expanderar denna till en rad per order?
Viktigaste slutsatserna om nästlad JSON
Hantering av nästlad JSON i R kräver en verktygslåda i flera lager:
fromJSON(json, flatten = TRUE)— plattar automatiskt ut en nivå av nästlingfromJSON(json, simplifyDataFrame = FALSE)— ger en lista av listor för manuell bearbetning- Nästlade arrayer → listkolumner i den resulterande dataramen
purrr::map_chr/dbl/int(list, 'field')— extraherar typade värden från varje element- Kedjade anrop till
map()går igenom djupt nästlade nivåer tidyr::unnest(df, cols = col)— expanderar listkolumner som innehåller dataramarjsonlite::flatten(df)— plattar ut nästlade dataramkolumner efter parsning- Hantera alltid
NULLmedif (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)Lär dig R med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 43
- Lektioner
- 159
Vanliga frågor
Är lektionen ”Hantera nästlade JSON-strukturer” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen R Academy, inklusive ”Hantera nästlade JSON-strukturer”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i R Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Hantera nästlade JSON-strukturer”?
Platta ut djupt nästad JSON till tidy data frames för analys. Ni övar på R Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig R Academy?
Du behöver inga förkunskaper. Utbildningen i R Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.
Hur lång tid tar lektionen ”Hantera nästlade JSON-strukturer”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här R Academy-lektionen?
Ja. Varje R Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Tolka JSON med jsonlite
- Skicka HTTP-förfrågningar med httr2
- Anropa REST-API:er i R
- Hantera nästlade JSON-strukturer