Search code examples
javascriptnode.jsmongodbmernrailway

How to use MongoDB cli database tools in railway?


in a current MERN stack project (github repo) I am trying to implement a mechanism that resets two documents in my mongo db to default data once a day at midnight to reset changes made by others to the live website of the project. For this I use the mongodb cli database tools to import the corresponding two .json files with the respective data using the command mongoimport.

code excerpt from db.js:

const Comment = require('../models/commentModel');
const User = require('../models/userModel');

const restoreDefaultData = async () => {
    const { spawn } = require('child_process');
    const restoreCollection = (collectionName) => {
        const restoreProcess = spawn('mongoimport', [
            `--uri="${process.env.MONGO_URI}"`,
            `--collection=${collectionName}`,
            `--file=./.mongodb/default-data/${collectionName}.json`,
            '--jsonArray'
        ]);

        restoreProcess.on('exit', (code, signal) => {
            // handle success and error messages
        });
    };

    // first delete all comment data and then restore the default comment data
    await Comment.deleteMany({});
    restoreCollection('comments');

    // first delete all user data and then restore the default user data
    await User.deleteMany({});
    restoreCollection('users');
};

In my local project this works without problems, because there are also the mongodb cli database tools installed. To provide the live website I use railway.

After the building process started with the command..

npm i --prefix frontend && npm run build --prefix frontend

..I now get the following error in the building console:

node:events:491
throw er; // Unhandled 'error' event
^
Error: spawn mongoimport ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
Emitted 'error' event on ChildProcess instance at:
    at Process.ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
        errno: -2,
        code: 'ENOENT',
        syscall: 'spawn mongoimport',
        path: 'mongoimport',
        spawnargs: [
            '--uri="mongodb+srv://admin:[email protected]/app?retryWrites=true&w=majority"', '--collection=comments',
            '--collection=comments',
            '--file=./.mongodb/default-data/comments.json',
            '--jsonArray'
        ]
    }

How do I manage to use the mongodb cli database tools in my railway deployment? Or is there even another way to reset the two documents of the database daily to certain default data?

I already tried to include the download and installation process of the mongodb cli database tools in the railway build command but this ended up in an error as well.

Am slowly a little clueless and look forward to any answer!


Solution

  • Through an answer, which strangely has already been deleted, I have now come to the solution. I have thought too complicated and overlooked that mongoose provides the very simple function insertMany, with which you can easily push multiple documents into one collection. Another stumbling block was to transfer the data in the two JSON files from the extended JSON object format into a plain JSON object, but that also worked out with the BSON package somehow. You can now view the full result here.

    db.js

    const Comment = require('../models/commentModel');
    const User = require('../models/userModel');
    const { EJSON } = require('bson');
    
    const restoreDefaultData = async () => {
        const now = new Date().toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'medium' });
    
        // read comments data from default data file and convert it with EJSON module from extended JSON object to plain json object
        const commentsData = EJSON.deserialize(require('../../.mongodb/default-data/comments.json'));
        // delete all comment data in db and then restore the default comment data from the data file into the db
        await Comment.deleteMany({});
        await Comment.insertMany(commentsData);
        console.log(`[${now}] MongoDB restore process of ${'comments'.italic} data successfull`.cyan);
    
        // read users data from default data file and convert it with EJSON module from extended JSON object to plain json object
        const usersData = EJSON.deserialize(require('../../.mongodb/default-data/users.json'));
        // delete all user data existing in db and then push the default user data from the data file into the db
        await User.deleteMany({});
        await User.insertMany(usersData);
        console.log(`[${now}] MongoDB restore process of ${'users'.italic} data successfull`.cyan);
    };