3

I am building an api at the moment which has several layers of information. At the moment I am using tibbles and nesting the information under columns:

# A tibble: 1 x 3
  APICallTimeGMT      Error                some_data       
  <dttm>              <list>               <list>          
1 2018-10-19 11:43:10 <data.frame [1 × 2]> <tibble [2 × 3]>

When I then turn this into JSON using jsonlite::toJSON, I get a lot list [] brackets. Is there a way to turn these specific objects into a json object instead of a list. So, what class (instead of data.frame) should the nested object be?

Current output:

enter image description here

Desired Output:

enter image description here

Here is the dput(x) for reproducibility:

structure(list(APICallTimeGMT = structure(1539949390.26164, class = c("POSIXct", 
"POSIXt")), Error = list(structure(list(msg = structure(1L, .Label = "OK", class = "factor"), 
    status = 200), .Names = c("msg", "status"), row.names = c(NA, 
-1L), class = "data.frame")), some_data = list(structure(list(
    Outcome = c("Case1", "Case2"), predictions = list(structure(list(
        ClassA = 0.4, ClassB = 0.1, ClassC = 0.5), .Names = c("ClassA", 
    "ClassB", "ClassC"), row.names = c(NA, -1L), class = "data.frame"), 
        structure(list(ClassA = 0.4, ClassB = 0.1, ClassC = 0.5), .Names = c("ClassA", 
        "ClassB", "ClassC"), row.names = c(NA, -1L), class = "data.frame")), 
    meta = list(structure(list(model = structure(1L, .Label = "Awesome AI", class = "factor"), 
        runs = 55), .Names = c("model", "runs"), row.names = c(NA, 
    -1L), class = "data.frame"), structure(list(model = structure(1L, .Label = "Awesome AI", class = "factor"), 
        runs = 55), .Names = c("model", "runs"), row.names = c(NA, 
    -1L), class = "data.frame"))), row.names = c(NA, -2L), class = c("tbl_df", 
"tbl", "data.frame"), .Names = c("Outcome", "predictions", "meta"
)))), row.names = c(NA, -1L), .Names = c("APICallTimeGMT", "Error", 
"some_data"), class = c("tbl_df", "tbl", "data.frame"))
Hanjo Odendaal
  • 1,395
  • 2
  • 13
  • 32

2 Answers2

2

The answer from Stéphane Laurent was close. It would seem that the problem is that if the data is within nested tibbles, auto-unbox = TRUE, somehow fails. To print the data above correctly, I used mutate + purrr:

library(jsonlite)

x_unboxed <- x %>% 
  mutate(Error = map(Error, ~.x %>% unbox),
         some_data = map(some_data, ~.x %>% 
                           mutate(predictions = map(predictions, ~.x %>% unbox),
                                  meta = map(meta, ~.x %>% unbox)))) %>% 
  unbox

x_unboxed %>% toJSON(., pretty = T)
Hanjo Odendaal
  • 1,395
  • 2
  • 13
  • 32
  • Ah nice, you've found a solution. I have just written an ugly solution (converting each dataframe to a list), but no need to post it now. I didn't know the `unbox` function. – Stéphane Laurent Oct 19 '18 at 16:16
1

In the simple case where you're just using lists, the auto_unbox flag does do the trick:

> jsonlite::toJSON(list(name = "test", value = 2))
{"name":["test"],"value":[2]} 
> jsonlite::toJSON(list(name = "test", value = 2), auto_unbox=TRUE)
{"name":"test","value":2} 

I'm glad I could see @Stéphane Laurent's deleted answer as this is the common answer to this question.

mbauman
  • 30,958
  • 4
  • 88
  • 123