Mongodb: A complete guide about MongoDB, MongoDB with Node JS, Mongodb Replication and shading concept

Tuesday, December 24, 2019

Mongodb: A complete guide about MongoDB, MongoDB with Node JS, Mongodb Replication and shading concept


Most people meet MongoDB believing it is "SQL without the schema" — a place to dump JSON when you can't be bothered to design tables. That framing is why so many MongoDB projects rot into slow, inconsistent, un-queryable blobs a year in.

MongoDB is not a schema-less escape hatch. It is a document database that rewards you for modelling around how your application reads and writes data, not around normalized relations. Get that one idea right and everything below — indexing, aggregation, replication, sharding — falls into place.

MongoDB complete guide
MongoDB — Document Model, Querying, Scaling

The below topics are covered in this blog -

1. What MongoDB actually is
2. How MongoDB stores data (vs an RDBMS)
3. When to reach for MongoDB — and when not to
4. Inserting data
5. Reading data: find, projection, $and / $or
6. Sort, count, skip & limit
7. Updating data
8. Deleting data
9. Indexing — the difference between fast and unusable
10. Aggregation pipelines
11. Replication & high availability
12. Sharding & horizontal scale
13. Backup & restore
14. Connecting MongoDB from Node.js
15. Common Mistakes
16. The Takeaway

1. What MongoDB actually is

MongoDB is an open-source, document-oriented NoSQL database first released in 2009 by the company now called MongoDB, Inc. Instead of rows in tables, it stores documents — JSON-like structures — grouped into collections. On disk those documents are held as BSON (Binary JSON), which adds types JSON lacks, such as native dates, 64-bit integers, and binary data.

The practical consequence: a single document can hold nested objects and arrays, so data your application uses together can be stored together and fetched in one read — no joins across five tables to render one screen.

2. How MongoDB stores data (vs an RDBMS)

A relational database stores data in tables with a fixed, pre-declared schema and uses SQL plus foreign keys to relate rows across tables. MongoDB stores self-contained documents whose shape you can vary field-by-field, and it favours embedding related data over splitting it across collections.

Dimension Relational (RDBMS) MongoDB
Unit of storageRow in a tableDocument in a collection
SchemaFixed, declared up frontFlexible per document (still worth designing)
RelationshipsJoins on foreign keysEmbedding, or references + $lookup
Read patternAssemble from many tablesOne document, one read (when modelled well)
ScalingVertical first; sharding is hardHorizontal via native sharding
TransactionsMature, multi-row defaultMulti-document transactions supported (since 4.0)
Best fitComplex relational integrity, reportingEvolving shapes, high write volume, nested data
Worst fitRapidly changing, sparse schemasHeavy ad-hoc cross-entity joins

3. When to reach for MongoDB — and when not to

Good fits: content management and catalogs, e-commerce product data with varying attributes, user profiles and activity feeds, social and messaging data, IoT / event ingestion where write throughput matters, and any domain where the document shape genuinely differs row to row.

Think twice when your core workload is heavy multi-entity joins, strict cross-table financial integrity, or complex ad-hoc reporting — a relational engine is usually the calmer choice there. "We might need to scale" is not, by itself, a reason to pick MongoDB.

4. Inserting data

Insert a single document, or many at once:

// one document
db.employee.insertOne({
  emp_id: 1,
  name: "Atique",
  age: 30,
  dept: "IT",
  skills: ["nodejs", "angular", "mongodb"],
  leaves: { CL: 10, SL: 10, PL: 21 }
})

// many documents
db.employee.insertMany([
  { emp_id: 2, name: "Sunny", dept: "Testing", skills: ["jira"] },
  { emp_id: 3, name: "Sonu",  dept: "IT",      skills: ["nodejs", "mongodb"] }
])

5. Reading data: find, projection, $and / $or

The second argument to find() is the projection — ask only for the fields you need, never the whole document out of habit:

// filter + projection (1 = include, 0 = exclude)
db.employee.find({ dept: "IT" }, { name: 1, skills: 1, _id: 0 })

// OR
db.employee.find({ $or: [ { age: { $gt: 40 } }, { emp_id: { $gt: 10 } } ] }).count()

// AND
db.employee.find({ $and: [ { age: { $gt: 40 } }, { emp_id: { $gt: 10 } } ] }).count()

6. Sort, count, skip & limit

These chain onto a cursor and are the backbone of pagination:

db.employee.find().sort({ email: -1 })   // -1 descending, 1 ascending
db.employee.find({}).count()
db.employee.find().skip(10).limit(10)    // page 2 at 10 per page

One caveat worth knowing early: skip() on large offsets is expensive because the server still walks the skipped documents. For deep pagination, page on an indexed field with a range filter instead of a large skip.

7. Updating data

db.employee.updateOne({ emp_id: 42 }, { $set: { dept: "HR" } })
db.employee.updateMany({ dept: "HR" }, { $set: { dept: "IT" } })

// replaceOne swaps the whole document (except _id) - use with care
db.employee.replaceOne({ dept: "business" }, { dept: "sales" })

Always pair an update filter with the field you intend to change via $set. A common accident is passing a bare document to an update and wiping every other field.

8. Deleting data

db.employee.deleteOne({ dept: "HR" })
db.employee.deleteMany({ dept: "business" })

9. Indexing — the difference between fast and unusable

Without an index, MongoDB scans every document in a collection to satisfy a query — a collection scan. On a few hundred documents you won't notice. On a few hundred thousand, your query is a full table read on every request.

// create an index (ascending)
db.employee.createIndex({ emp_id: 1 })

// compound index - order of fields matters for which queries it serves
db.employee.createIndex({ dept: 1, age: -1 })

// drop an index
db.employee.dropIndex({ emp_id: 1 })

// see whether a query used an index or scanned everything
db.employee.find({ emp_id: 500 }).explain("executionStats")

Note: createIndex() is the current method. The old ensureIndex() you'll see in older tutorials is deprecated — it still works as an alias, but write new code with createIndex(). Reach for explain() whenever a query feels slow; it tells you the truth about index use.

10. Aggregation pipelines

Aggregation is MongoDB's answer to SQL's GROUP BY plus much more — a pipeline of stages where each stage transforms the stream of documents and hands it to the next.

// count documents per gender
db.school.aggregate([
  { $group: { _id: "$gender", total: { $sum: 1 } } }
])

// max / min age per gender
db.school.aggregate([
  { $group: { _id: "$gender", oldest: { $max: "$age" }, youngest: { $min: "$age" } } }
])

// a fuller pipeline: filter, then group, then sort
db.orders.aggregate([
  { $match: { status: "paid" } },
  { $group: { _id: "$customerId", spend: { $sum: "$amount" } } },
  { $sort: { spend: -1 } },
  { $limit: 10 }
])

11. Replication & high availability

Replication keeps synchronized copies of your data across multiple servers, called a replica set. One node is the primary (takes all writes); the rest are secondaries that copy the primary's operation log.

The primary emits a heartbeat. If the secondaries stop hearing it, they hold an election and promote one of themselves to primary — automatic failover with no data loss for acknowledged writes. This is what protects you from losing a single server, and it's why production MongoDB is essentially always a replica set, never a standalone node.

MongoDB replication and failover
MongoDB Replication — primary, secondaries, and failover

12. Sharding & horizontal scale

When one machine can no longer hold the data or serve the read/write throughput, sharding spreads the data across many machines — horizontal scaling. Each shard is itself a replica set. A mongos router sits in front and, using the shard key, decides which shard a given query or write belongs to.

The shard key is the single most important design decision here. A poorly chosen key funnels most traffic to one shard (a "hot shard") and you lose the benefit of scaling out. Choose a key with high cardinality and even access distribution.

13. Backup & restore

For logical backups, mongodump writes BSON dumps and mongorestore reads them back:

# entire server
mongodump
mongorestore

# a single database
mongodump --db mongodbTutorial
mongorestore --db mongodbTutorial dump/mongodbTutorial

# a single collection
mongodump --db mongodbTutorial --collection school
mongorestore --db mongodbTutorial --collection school dump/mongodbTutorial/school.bson

For anything production-grade, prefer a real backup strategy — scheduled snapshots, or MongoDB Atlas continuous backups — over a manual mongodump you have to remember to run.

14. Connecting MongoDB from Node.js

The common path in a Node app is Mongoose. Keep the connection in its own module and export it:

// db.js
const mongoose = require("mongoose");

mongoose.connect(process.env.MONGODB_URI)
  .then(() => console.log("MongoDB connected..."))
  .catch((err) => console.error("DB connection error:", err));

module.exports = mongoose;

Two modern notes on older tutorials: the useNewUrlParser and useUnifiedTopology options are no longer needed on current driver versions, and the connection string belongs in an environment variable, never hardcoded with an IP and port in source.

15. Common Mistakes

1. Treating "schema-less" as "design-less." MongoDB lets you skip a schema; it does not reward you for it. Model documents around your read patterns or you'll pay for it in every query later.

2. Querying without indexes. The demo runs fine, then production melts under collection scans. Index the fields you filter and sort on, and confirm with explain().

3. Unbounded array growth inside a document. Embedding is great until a document grows without limit (comments, events). Documents have a 16MB cap — past a point, reference a separate collection instead.

4. Choosing a low-cardinality shard key. Sharding on something like country or a boolean creates hot shards. Pick a key that spreads load evenly.

5. Running a standalone node in production. No replica set means no failover and no safe backups. A single mongod is for local development only.

16. The Takeaway

MongoDB pays off when you model with intent: shape documents around how the app reads them, index for your real queries, run a replica set for safety, and reach for sharding only when a single machine genuinely can't cope. The flexibility is real — but it's a tool for good design, not a substitute for it.

About the author

I'm Atique Ahmed, Principal AI Architect — 7x Microsoft MVP and a Guinness World Record holder for Programming Excellence. I write about GenAI, agentic AI, and the systems that hold real applications together.

Find more at atiqueahmed.com · LinkedIn · GitHub

0 comments :