Могу ли я использовать метод jsonlite:toJSON для преобразования фрейма данных или tibble в этот конкретный формат глубоко вложенного JSON?

#r #json #dataframe

Вопрос:

Я работаю с API Orbitly, и их API требует строки JSON в этом конкретном формате:

 {
    "requests": [
        {
            "params": {
                "email": ["steve@woz.org"]
            }
        },
        {
            "params": {
                "profile": ["https://www.linkedin.com/in/brianchesky/"]
            }
        },
        {
            "params": {
                "phone": ["17186893174"]
            }
        },
        {
            "params": {
                "name": ["marc benioff"],
                "company": ["salesforce"]
            }
        }
    ],
    "required": "profiles.network:linkedin AND (phone_numbers OR emails)"
}
 

Мои данные в настоящее время находятся в этом формате (импортированы из электронной таблицы).:

 > df
# A tibble: 4 x 5
  email         profile                                  phone       name         company   
  <chr>         <chr>                                    <chr>       <chr>        <chr>     
1 steve@woz.org NA                                       NA          NA           NA        
2 NA            https://www.linkedin.com/in/brianchesky/ NA          NA           NA        
3 NA            NA                                       17186893174 NA           NA        
4 NA            NA                                       NA          marc benioff salesforce
 

Если я вызову jsonlite::toJSON метод, я смогу преобразовать фрейм данных/tibble в формат, который в некотором роде близок, но, по понятным причинам, он ничего не объединяет в списки, и, насколько я могу судить, нет никакого способа заставить toJSON использовать несколько неестественное объединение params перед всем:

 > print(toJSON(df, simplifyVector=FALSE, pretty=TRUE))
[
  {
    "email": "steve@woz.org"
  },
  {
    "profile": "https://www.linkedin.com/in/brianchesky/"
  },
  {
    "phone": "17186893174"
  },
  {
    "name": "marc benioff",
    "company": "salesforce"
  }
] 
 

Является ли моя единственная надежда на то, что этот фрейм данных будет сохранен в правильном формате, каким-то добавлением строки вручную? Или есть более умный способ применить этот toJSON метод?

Ответ №1:

 jsonlite::toJSON(list(
    requests=unname(do.call(Map, c(list(f=function(...) list(params = Filter(Negate(is.na), list(...)))), df))), 
    required="profiles.network:linkedin AND (phone_numbers OR emails)"), 
  pretty = TRUE)
# {
#   "requests": [
#     {
#       "params": {
#         "email": ["steve@woz.org"]
#       }
#     },
#     {
#       "params": {
#         "profile": ["https://www.linkedin.com/in/brianchesky/"]
#       }
#     },
#     {
#       "params": {
#         "phone": ["17186893174"]
#       }
#     },
#     {
#       "params": {
#         "name": ["marc benioff"],
#         "company": ["salesforce"]
#       }
#     }
#   ],
#   "required": ["profiles.network:linkedin AND (phone_numbers OR emails)"]
# } 
 

Данные

 df <- structure(list(email = c("steve@woz.org", NA, NA, NA), profile = c(NA, "https://www.linkedin.com/in/brianchesky/", NA, NA), phone = c(NA, NA, "17186893174", NA), name = c(NA, NA, NA, "marc benioff"), company = c(NA, NA, NA, "salesforce")), class = "data.frame", row.names = c(NA, 4L))
 

Комментарии:

1. Разве это не разбивает строки, если в них есть данные нескольких переменных? В требуемом формате API marc benioff и salesforce находятся вместе в JSON.

2. Я понял после того, как мой пример был сломан, и не показал этого. Мои извинения за это. Я думаю, что ваш ответ все еще очень близок к тому, что я ищу. Извините, я должен был убедиться, что вопрос был точным, так что извините, что отредактировал его постфактум.

3. Ваше последнее редактирование ничего не сделало, чтобы продемонстрировать этот эффект или то, что вы ожидаете от него. Я не использовал df в вашем вопросе, поэтому изменение этого не изменило того, как это работает.

4.Я не знаю, смогу ли я вместить здесь всю строку, но использование вашего df кода и вашего кода создает строку, включающую следующее: {"params": {"name": ["marc benioff"]}},{"params": {"company": ["salesforce"]}} в то время как это должно привести к чему-то подобному в моем вопросе, с этим: {"params": {"name": ["marc benioff"],"company": ["salesforce"]}} . Точки данных, которые находятся в той же строке в данных (как и в ваших df тоже), должны быть в конечном результате такими же params , как в документации API.

5. Спасибо. Я сохранил результат как df_as_json , а затем вызвал df_as_json$required <- unbox(df_as_json$required) , потому что этот API требует, чтобы все было в списке, кроме required параметра. Однако ваш код был именно тем, что мне было нужно! Спасибо!