Updating A JSON File without over-writing it
Hey everyone,
I'm using JSON files to store data that I use across multiple scripts.
I noticed that if you write data to a JSON (that is named the same, etc...), the data get's overwritten, not updated.
I'm trying to add a nifty little thing to my mix delivery routines. Basically, I want to create an empty JSON file when I'm setting up the project, and every time I print a version of the mix, I want to add data to that JSON.
Does anybody know how I could do this? The only way I figured was to read the JSON first, do a bit of object construction and then over-write the existing JSON. It just sounds cumbersome and not very elegant to me.
I wonder if @raphaelsepulveda or @Kitch have an idea :)
Thanks in advance guys!
- marcello azevedo @marcello_azevedo
I’ll be following this one.
- TThomas Gloor @Thomas_Gloor
@marcello_azevedo , in the meantime I'm working on the not elegant way to do it!
- In reply toThomas_Gloor⬆:Chris Shaw @Chris_Shaw2024-02-17 16:32:20.809Z
The only way I figured was to read the JSON first, do a bit of object construction and then over-write the existing JSON.
That is exactly the way it is done.
Read the file, modify/add to it, then save.
I would do some research on how to use different methods to modify objects (the spread operator is especially useful here )- TThomas Gloor @Thomas_Gloor
Hey Chris!
Thank you for answering. Glad I found out by myself :D but thanks for confirming!
- In reply toThomas_Gloor⬆:Raphael Sepulveda @raphaelsepulveda2024-02-17 21:27:44.221Z
@Thomas_Gloor, I know what you mean. I felt the same way when I first learned how to handle JSON files.
But like @Chris_Shaw already mentioned, it sounds like you're already going about it the right way.I'm not exactly sure what you're trying to do but here are a few simple examples:
This is how you create an empty JSON file:
// Creating an empty JSON file sf.file.writeJson({ json: {}, path: "~/Downloads/mixDeliveryRoutine.json" });
Add properties:
// Read the JSON file let mixDeliveryRoutine = sf.file.readJson({ path: "~/Downloads/mixDeliveryRoutine.json" }).json; // Add properties (simple way) mixDeliveryRoutine.songName = "My Awesome Mix Name"; mixDeliveryRoutine.mainMix = true; // Update the JSON file sf.file.writeJson({ json: mixDeliveryRoutine, path: "~/Downloads/mixDeliveryRoutine.json" });
Update properties:
// Read the JSON file let mixDeliveryRoutine = sf.file.readJson({ path: "~/Downloads/mixDeliveryRoutine.json" }).json; // Update existing properties (simple way) mixDeliveryRoutine.songName = "Updated Awesome Mix Name"; mixDeliveryRoutine.mainMix = false; // Update the JSON file sf.file.writeJson({ json: mixDeliveryRoutine, path: "~/Downloads/mixDeliveryRoutine.json" });
Add/Update properties using the spread operator:
// Read the JSON file let mixDeliveryRoutine = sf.file.readJson({ path: "~/Downloads/mixDeliveryRoutine.json" }).json; // Add/Update properties (using the spread operator) mixDeliveryRoutine = { ...mixDeliveryRoutine, // Bring in existing properties in object mainMix: true, altMix: false, stems: true, }; // Updating the JSON file sf.file.writeJson({ json: mixDeliveryRoutine, path: "~/Downloads/mixDeliveryRoutine.json" });
(please read more about the spread operator to understand the limitations in this use case—shallow copy)
Hopefully that all makes sense.
- TThomas Gloor @Thomas_Gloor
Hey Raphael!
Thank you so much for expanding! I'm gonna dig the spread operator!
- In reply toraphaelsepulveda⬆:Comment deleted
- TThomas Gloor @Thomas_Gloor
Here's what I came up with! updated it today, it is slightly more complicated as fare as object structure, but it makes the JSON file more readable.
// Generated by a function in the bigger script... let info = { titleName: "SONG", mixVersion: "V1", mixPass: "MAIN MIX", mixDate: "28.02.2024", mixPrintTime: "12:04:24", sentToClient: "Yes" } let titleMixLogData = { passInfo: { mixDate: info.mixDatemixDate, mixPrintTime: info.mixPrintTime, sentToClient: info.sentToClient, } } let mixLogJSONPath = "YOUR PATH" ////////////////////////////////////////////////// CALL FUNCTION createAndUpdateMixLog({ mixLogJSONPath: mixLogJSONPath, titleMixLog: titleMixLogData, titleName: info.titleName, mixVersion: info.mixVersion, mixPass: info.mixPass }) let mixLogJson = sf.file.readJson({path: mixLogJSONPath}).json ////////////////////////////////////////////////// UPDATE MIX LOG JSON function createAndUpdateMixLog({ mixLogJSONPath, titleMixLog, titleName, mixVersion, mixPass }) { let mixLogJSONExists = sf.file.exists({ path: mixLogJSONPath }).exists // If the Mix Log JSON wasn't created yet, create it and initialize an empty array in it if (!mixLogJSONExists) { sf.file.writeJson({ path: mixLogJSONPath, json: {} }) } let mixLogJSONData = sf.file.readJson({ path: mixLogJSONPath, onError: "Continue", }).json if (!mixLogJSONData[titleName]) { mixLogJSONData[titleName] = {}; } // Create Title Name Property, to house mixVersion/mixPass Objects mixLogJSONData[titleName][mixVersion + "-" + mixPass] = titleMixLog let writeToMixLogJSON = sf.file.writeJson({ json: mixLogJSONData, path: mixLogJSONPath, }).success if (!writeToMixLogJSON) { alert("Error writing data to Mix Log") } else if (!mixLogJSONExists) { log("Mix Log file successfully created and updated") } else { log("Mix log file successfully updated") } } ////////////////////////////////////////////////// GET CURRENT TIME function getCurrentTime() { let currentDateAndTime = new Date(); let timeVariable = currentDateAndTime.toTimeString().split(' ')[0].split(':').join(':'); return timeVariable } ````
Raphael Sepulveda @raphaelsepulveda2024-02-17 22:54:04.685Z
Yes, approaching it as an object literal (like you've done here) instead of an array is the better approach 👍🏼
- TThomas Gloor @Thomas_Gloor
I had doubt about whether to use an array or an object, as it's easier to iterate through arrays, but in the end, this JSON is made to be read, not used, so the object literal makes it more easily readable.
Thank you again for your (constant) help Raphael!