MongoDB from Node

Connect Node to MongoDB with the official driver — including the panel's authSource connection string — and do the full CRUD: insert, find, update with $inc, and delete, with one reusable client.

MongoDB stores documents — flexible, JSON-like records — instead of rows in fixed tables. It's one of the three managed database types on Falix, and a natural fit when your data doesn't want a rigid schema. This guide connects Node to it with the official mongodb driver and runs the full set of create-read-update-delete operations.

At a glance
You need a MongoDB database (managed or your own server) and a Node.js app server
Plan any
Time about twenty-five minutes

This goes deeper than Connect your app to a database, which introduced the connection. New to how databases fit a bot? See Designing tables for your bot — the shapes apply to collections too.

Setup: the connection string (mind the authSource)

The panel gives you a MongoDB string shaped like this:

mongodb://user:pass@host:port/dbname?authSource=dbname

Copy it from the Databases page into your .env as DATABASE_URL (why not in code), and install the driver from the Packages page (search mongodb, install, restart).

🎯 Good to know: The ?authSource=dbname on the end is not optional — it tells MongoDB which database holds your user account. On a managed Falix database that's your own database, so authSource matches the database name. Drop it and you'll get an authentication error even with the right password. Keep the string exactly as the panel gives it.

Connect once, reuse everywhere

The mongodb client pools connections internally, so you create it once and share it — never open one per request:

const { MongoClient } = require('mongodb');

const client = new MongoClient(process.env.DATABASE_URL);

async function main() {
  await client.connect();
  const db = client.db();               // the database from the connection string
  const users = db.collection('users'); // a collection is like a table

  // ... operations go here ...

  await client.close();
}

main().catch(console.error);

client.db() with no argument uses the database named in your connection string. A collection is Mongo's equivalent of a table — but you don't create it or define columns first; it springs into existence the moment you insert a document.

The full CRUD

Everything below was verified on Falix's Node image against MongoDB 7. Drop it into the main() above:

// CREATE — insert one document
await users.insertOne({ _id: 'alice', coins: 100, roles: ['member'] });

// READ — find one by its id
console.log(await users.findOne({ _id: 'alice' }));
// { _id: 'alice', coins: 100, roles: [ 'member' ] }

// UPDATE — $inc adds to a number; upsert creates the doc if missing
await users.updateOne({ _id: 'alice' }, { $inc: { coins: 25 } });
await users.updateOne({ _id: 'bob' }, { $inc: { coins: 10 } }, { upsert: true });

// READ MANY — filter, sort, collect
console.log(await users.find({}).sort({ coins: -1 }).toArray());
// [ { _id: 'alice', coins: 125, ... }, { _id: 'bob', coins: 10 } ]

// DELETE — remove one
await users.deleteOne({ _id: 'bob' });
console.log(await users.countDocuments()); // 1

The parts worth knowing:

  • _id is every document's unique key. Set it yourself (a Discord user ID makes a perfect _id) or let Mongo generate one. It's automatically indexed, so lookups by _id are fast.
  • A document is just an object — nested arrays and objects (roles: ['member']) are stored as-is, no separate table needed. That flexibility is Mongo's whole appeal.
  • Update operators like $inc (add to a number), $set (change a field), and $push (append to an array) change a document in place. $inc is atomic, which is what you want for a balance or a counter.
  • upsert: true turns an update into "update if it exists, otherwise create it" — the same first-seen-user convenience as a SQL upsert.
  • find() returns a cursor, not the data. Chain .sort(), .limit(), and finish with .toArray() to get the documents.

No schema, but still design your shape

Mongo won't enforce a schema, but that doesn't mean skipping the thinking. Decide up front what each document holds and keep it consistent — a users collection where some docs call it coins and others balance is a bug waiting to happen. The table-design shapes — one document per user, per guild, a separate collection for lists — apply here just as they do in SQL.

Verify it works

Start the server and watch the Console. The snippet prints the document it inserted, then the sorted list after the updates, then a final count of 1. Seeing coins: 125 on alice after the $inc — the round trip from code to Mongo and back — is your success signal. Restart the app and query again: the documents are still there, because a managed database outlives your server.

Troubleshooting

  • Authentication failed — almost always the missing or wrong authSource. Use the panel's string verbatim, including ?authSource=dbname. If you rotated the password, copy the fresh string into .env.
  • ECONNREFUSED / server selection timed out — wrong host or port, or the database is unreachable. Use the exact host from the database page; for your own Mongo server, use its public address and check it's running.
  • Cannot find module 'mongodb' — install it on the Packages page and restart.
  • E11000 duplicate key error — you inserted a document whose _id already exists. Use updateOne with upsert: true instead of a second insertOne.

Beyond connecting, this is all standard driver territory — the official MongoDB Node.js driver docs cover aggregation, transactions, and indexes.


Next steps

Was this guide helpful?