skip to Main Content

I’m writing an init script (e.g. /docker-entrypoint-initdb.d/init.js) which will be executed by the mongo Docker image when the container is first created. (See the docs for the image, "Initializing a fresh instance" section.)

Within this script, I need to open a file from disk (on the container), and then insert an object into the database with that file’s content as a property. Something like this:

import fs from "fs";

let data = fs.readFileSync("/path/to/somefile.txt", { encoding: "base64" });

db.example.files.insertOne({
  filename: "somefile.txt",
  data: Binary.createFromBase64(data),
});

But this script is written for NodeJS — how can I do the same in a plain JS script executed via MongoDB directly (e.g. mongosh -f init.js)?

2

Answers


  1. Your init.js script, with some minor changes, will work in MongoDB 6.0.15 & 7.0.9. Probably since the NodeJS environment is available during startup.

    TL;DR: Remove the fs import.

    Changes needed:

    1. All the files, including somefile.txt, need to be mounted/linked in docker-compose volumes
    2. The fs import is should be removed 🤔
      • It throws an error and the service doesn’t come up:
      • TypeError: Cannot assign to read only property 'message' of object 'SyntaxError: 'import' and 'export' may appear only with 'sourceType: "module"' (1:0)
    3. Specify the DB with getSiblingDB, otherwise it goes under the test and the collection name becomes example.files; unless that’s what you wanted.

    docker-compose.yml

    services:
      mongo:
        image: mongo:6  # also works with 7
        # image: mongodb/mongodb-community-server:7.0-ubuntu2204  # also works
        volumes:
          - ./db:/data/db
          - ./init.js:/docker-entrypoint-initdb.d/init.js:ro
          - ./somefile.txt:/docker-entrypoint-initdb.d/somefile.txt:ro
        environment:
          MONGO_INITDB_ROOT_USERNAME: root
          MONGO_INITDB_ROOT_PASSWORD: example
        ports:
          - "27017:27017"
    

    init.js

    let data = fs.readFileSync("./docker-entrypoint-initdb.d/somefile.txt", { encoding: "base64" });
    
    db.getSiblingDB("example").files.insertOne({
      filename: "somefile.txt",
      data: Binary.createFromBase64(data),
    });
    

    Contents of somefile.txt:

    text in somefile
    
    

    Result in the DB after first startup:

    loaded record in the DB

    Login or Signup to reply.
  2. For MongoDB 5.x and 4.x, this needs to be done in a Shell script, instead of JS. And you’ll need to use BinData with subtype 0, instead of Binary.createFromBase64. The final result is the same in the DB.

    docker-compose.yml

    services:
      mongo:
        image: mongo:5  # also works with 4.4, 4.2, 4.0
        # image: mongodb/mongodb-community-server:4.4.0-ubuntu2004  # also works
        volumes:
          - ./db:/data/db
          - ./init.sh:/docker-entrypoint-initdb.d/init.sh:ro
          - ./somefile.txt:/docker-entrypoint-initdb.d/somefile.txt:ro
        environment:
          MONGO_INITDB_ROOT_USERNAME: root
          MONGO_INITDB_ROOT_PASSWORD: example
        ports:
          - "27017:27017"
    

    init.sh for MongoDB 5.x

    INIT_BASE64_DATA=$(cat ./docker-entrypoint-initdb.d/somefile.txt | base64)
    
    mongosh admin <<EOF
        use example
        db.files.insertOne({ 
          filename: "somefile.txt", 
          data: BinData(0, "$INIT_BASE64_DATA") 
        });
    EOF
    

    init.sh for MongoDB 4.x, change the mongosh to mongo:

    INIT_BASE64_DATA=$(cat ./docker-entrypoint-initdb.d/somefile.txt | base64)
    
    mongo admin <<EOF
        use example
        db.files.insertOne({ 
          filename: "somefile.txt", 
          data: BinData(0, "$INIT_BASE64_DATA") 
        });
    EOF
    
    

    Contents of somefile.txt:

    text in somefile
    
    

    Result in the DB after first startup:

    loaded record in the DB

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search