Search code examples
node.jsdiscord.jsfs

Use fs to modify a single part of a json file, rather than overwriting the entire thing


For a Discord bot, I currently have a command that displays info for our DnD sessions:

pictured.

The data is stored in a dndinfo.json file thats looks like this:

{"time":"**18:00 UK time**",
"date":"**14/05/20**",
"dm":"**Mannion**",
"prime":"Playing",
"smurphy":"Playing",
"calle":"Playing",
"smardon":"Playing",
"james":"Playing",
"mannion":"DMing",
"dex":"Playing",
"module":"Hoard of the Dragon Queen"}

I want users to be able to do a command, such as '!te time 17:00', which will update the time accordingly.

I currently am working with this code:

const Discord = module.require('discord.js');
const fs = require('fs');
const dndinfo = require ('../../dndinfo.json');

module.exports = {
    name: 'test',
    aliases: ['te'],
    category: 'dnd',
    description: 'Updates DnD info',
    usage: '!te',
    run: async (client, message, args) => {

        const time = dndinfo.time;
        let editMessage = message.content.slice(9);

        if (message.content.toLowerCase().includes('time')) {

            fs.readFile('dndinfo.json', function(err, data) {
                console.log(time);
                fs.writeFile('dndinfo.json', JSON.stringify(editMessage, null, 2), (err) => {
                    if (err) console.error;
                    message.channel.send ('message written');

                });
            });
        }
    },
};

When I run the command '!te time 17:00', the entire dndinfo.json file is replaced with:

"17:00"

I understand that it's because i'm using fs.writeFile but i'm not sure of how to specify only 'time' and have that updated?


Solution

  • There is no practical way to update just a piece of JSON in a file. It's just not the type of format or the layout on disk that makes that practical.

    The usual mechanism for updating what's in the file is to just write out the whole JSON structure with your modifications in place, replacing the original contents of the file with the new content. If you don't already have all the content you need to do that, then you would first read in the contents of the file, making your changes, then write it out.

    Here's a function that reads it in, parses the JSON to a Javascript object, modifies that object, converts back to JSON and writes it out.

    const fsp = require('fs').promises;
    
    async function udpateTimeInFile(time) {
        try {
            let data = await fsp.readFile('dndinfo.json');
            let obj = JSON.parse(data);
    
            // set whatever property or properties in the object that you are trying to change
            obj.time = time;
    
            await fsp.writeFile('dndinfo.json', JSON.stringify(obj));
            message.channel.send('message written');
         } catch(e) {
            // error handling here
            console.log(e); 
            message.channel.send('error writing new data');
            throw e;      // make sure caller can see the message
         }
    }