1

I have the following data structure with p1-24, with v1-v8 files for each 24 folders. Each JSON file contains 1 object with around 10 key/pair values (some values are lists, some strings, some numbers). Abbrv example:

> p1
> --p1_v1.json
> --p1_v2.json
> --p1_v3.json
> --p1_v4.json
> p2
> --p2_v1.json
> --p2_v2.json
> --p2_v3.json
> --p2_v4.json

Original json:

> { “Element1”: info, 
> “Element2”: info,
> “Element3”: [ 
> Info1,
> Info2,
> Info3]
> }

I need to add a key/value pair (the value is a list of 15 numbers) to every json file. So each json will contain a copy of the same additional element (which is not unique per file).

New element:

>  “AdditionalElement: [
> 0.998,
> 0.768,
> 0.394,
> 0.123]
> 
> 

So I’d like to end up with this for all of the json files

> “Element1”: info, 
> “Element2”: info,
> “Element3”: [ 
> Info1,
> Info2,
> Info3],
> “AdditionalElement: [
> 0.998,
> 0.768,
> 0.394,
> 0.123]
> }

I have tried using jsonStrings and $addproperty, which works perfectly for one json file. but I need to add the element to every json file and then save the edits back to the original files/ folders.

I have tried this: ` files <- list.files("P:/new", recursive=T, full.names = TRUE, pattern = 'sub.*\.json$') files

json_lst <- lapply(jsonString$new(files)

newlist <- lapply(jsonString$addProperty("newelement", "[5, 6, 3, 2, 7]")`

ubik_01
  • 23
  • 3

2 Answers2

1

Using a fromJSON / append / toJSON approach. We append the vector as a named list element. append defaults to after=length(x), so it's automatically appended to the end.

v <- c(.998, .768, .394, .123)  ## element to add to all JSONs


library(jsonlite)

res <- lapply(json_lst, \(x, y) toJSON(append(fromJSON(x), list(ADD=y)), pretty=TRUE), v)

Gives

res
# [[1]]
# {
#   "mpg": [21, 21, 22.8, 21.4],
#   "cyl": [6, 6, 4, 6],
#   "disp": [160, 160, 108, 258],
#   "hp": [110, 110, 93, 110],
#   "drat": [3.9, 3.9, 3.85, 3.08],
#   "wt": [2.62, 2.875, 2.32, 3.215],
#   "qsec": [16.46, 17.02, 18.61, 19.44],
#   "vs": [0, 0, 1, 1],
#   "am": [1, 1, 1, 0],
#   "gear": [4, 4, 4, 3],
#   "carb": [4, 4, 1, 1],
#   "ADD": [0.998, 0.768, 0.394, 0.123]
# } 
# 
# [[2]]
# {
#   "mpg": [18.7, 18.1, 14.3, 24.4],
#   "cyl": [8, 6, 8, 4],
#   "disp": [360, 225, 360, 146.7],
#   "hp": [175, 105, 245, 62],
#   "drat": [3.15, 2.76, 3.21, 3.69],
#   "wt": [3.44, 3.46, 3.57, 3.19],
#   "qsec": [17.02, 20.22, 15.84, 20],
#   "vs": [0, 1, 0, 1],
#   "am": [0, 0, 0, 0],
#   "gear": [3, 3, 3, 4],
#   "carb": [2, 1, 4, 2],
#   "ADD": [0.998, 0.768, 0.394, 0.123]
# } 
#
# [...]
#
# [[8]]
# {
#   "mpg": [15.8, 19.7, 15, 21.4],
#   "cyl": [8, 6, 8, 4],
#   "disp": [351, 145, 301, 121],
#   "hp": [264, 175, 335, 109],
#   "drat": [4.22, 3.62, 3.54, 4.11],
#   "wt": [3.17, 2.77, 3.57, 2.78],
#   "qsec": [14.5, 15.5, 14.6, 18.6],
#   "vs": [0, 0, 0, 1],
#   "am": [1, 1, 1, 1],
#   "gear": [5, 5, 5, 4],
#   "carb": [4, 6, 8, 2],
#   "ADD": [0.998, 0.768, 0.394, 0.123]
# } 

Note: To read in your actual .json files (I used the example below) do sth. like:

path <- '/path/to/json/folder/'
files <- list.files(path)
json_lst <- lapply(files, fromJSON)

To write back to file use

Map(write_json, res, paste0(path, 'new_', files))

Data:

json_lst <- lapply(0:7*4, \(i) toJSON(mtcars[(1:4) + i, ], pretty=TRUE))
jay.sf
  • 60,139
  • 8
  • 53
  • 110
  • Thank you for your reply! The issue is that I need them in one object in the JSON file - I can merge them like you have suggested but this causes issues for the next step. here it is like file 1: { "key1": value1, "key2": value2} add element: "key3":value3 I need to get to { "key1": value1, "key2": value2, "key3": value3} not { "key1": value1, "key2": value2}, { "key3": value3} – ubik_01 Mar 27 '23 at 10:26
  • @ubik_01 I believe that's exactly what I've provided, `{"mpg": 21.4, "cyl": 6, ..., "add_element": 0.123, "_row": "Hornet 4 Drive"}` is not separated. Perhaps you should provide sth. [reproducible](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610#5963610) as an [**edit**](https://stackoverflow.com/posts/75847912/edit) to your question, also the expected output. – jay.sf Mar 27 '23 at 10:38
  • yes it is the difference is that my new element is a single key:value pair and it is a list "newelement": [1.1, .343, .456, etc] Each json file I have has 1 object and to every file I want to add the same one element (as above), rather than a single unique value per object. I'm quite inexperienced with R so I'm not sure how to edit what you have done so that it works this way. – ubik_01 Mar 27 '23 at 14:00
0

You don't need to parse the JSON string to a R object if you use the jsonStrings package:

library(jsonStrings)

# initiate a JSON string
jstring <- jsonString$new("
  {
    \"foo\": \"hello\",
    \"bar\": {\"x\": 1, \"y\": 2},
    \"baz\": [9, 99, null]
  }
")

# you can also initiate from a file: `jsonString$new("p1_v1.json")`

# add a new property:
jstring$addProperty("Additional Element", "[6,7,8,9]")

# get the new JSON string
jstring$asString()

EDIT

For your files:

files <- list.files(...)

for(file in files) {
  jstring <- jsonString$new(file)
  jstring$addProperty("Additional Element", "[6,7,8,9]")
  string <- jstring$asString()
  writeLines(string, file)
}
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • thank you - this works well for editing one json but I cannot work out how to loop it for all of the files I have. I edited my question to include what I have tried at the bottom (using lapply). do you have any idea how I can apply edits to many files and save over them? (i.e. I don't need to rename the new edits because the originals are saved elsewhere). thank s in advance – ubik_01 Mar 28 '23 at 11:48