W3docs

MongoDB Get Started

Learn how to install MongoDB, connect with PyMongo, and perform basic CRUD operations in Python with clear, working examples.

This chapter introduces MongoDB and shows you how to use it from Python using the PyMongo driver. By the end you will have MongoDB installed, a working connection, and a clear picture of how to insert, query, update, and delete documents.

What is MongoDB?

MongoDB is a document database — a type of NoSQL database that stores records as JSON-like documents instead of rows and columns. Each document is a self-contained object that can have nested fields and arrays, which makes it a natural fit for data that does not fit neatly into a fixed schema.

Key characteristics:

  • Schema-flexible. Two documents in the same collection can have completely different fields.
  • Rich query language. Filter, project, sort, limit, and aggregate with a single driver call.
  • Horizontal scalability. Built-in sharding and replica sets handle large data volumes and high availability.
  • JSON-native. Documents are stored as BSON (Binary JSON), so Python dicts map directly to MongoDB documents.

When to choose MongoDB over a relational database

SituationGood fit?
Rapidly changing data shape (prototypes, APIs)Yes
Hierarchical / nested dataYes
Complex multi-table JOIN queriesPrefer SQL
Strong ACID transactions across many tablesPrefer SQL
Full-text search at scaleCombine with Elasticsearch

Installing MongoDB

Option 1 — Local installation

Download the MongoDB Community Server from mongodb.com/try/download/community, choose your OS, and follow the installer. Then start the server:

# macOS / Linux
mongod --dbpath /data/db

# Windows (PowerShell, run as Administrator)
mongod --dbpath "C:\data\db"

Verify MongoDB is running by opening a second terminal and running:

mongosh --eval "db.adminCommand('ping')"

Expected output:

{ ok: 1 }

Option 2 — Docker (quickest for development)

If you have Docker installed, you can skip local installation entirely:

docker run -d --name mongo -p 27017:27017 mongo:7

This pulls the official MongoDB 7 image and exposes port 27017 on your machine. Stop it with docker stop mongo.

Option 3 — MongoDB Atlas (cloud)

Atlas is MongoDB's fully-managed cloud service with a free tier. After signing up, copy the connection string from the dashboard — it looks like:

mongodb+srv://username:[email protected]/

You can use that URI anywhere you see mongodb://localhost:27017/ in this chapter.

Installing the PyMongo Driver

PyMongo is the official Python driver for MongoDB. Install it with pip:

pip install pymongo

To use MongoDB Atlas, also install the extras that include the DNS resolver:

pip install "pymongo[srv]"

Verify the installation:

import pymongo
print(pymongo.version)
# e.g. 4.7.3

Connecting to MongoDB

MongoClient is the entry point for all driver operations. Create one client per application and reuse it — the client manages an internal connection pool.

from pymongo import MongoClient

# Local server with default host and port
client = MongoClient("mongodb://localhost:27017/")

# Verify connectivity (raises ConnectionFailure if the server is unreachable)
client.admin.command("ping")
print("Connected successfully")

For production code, always handle connection errors explicitly:

from pymongo import MongoClient
from pymongo.errors import ConnectionFailure

client = MongoClient("mongodb://localhost:27017/", serverSelectionTimeoutMS=3000)

try:
    client.admin.command("ping")
    print("Connected to MongoDB")
except ConnectionFailure as e:
    print("Connection failed:", e)

Connection string format

mongodb://[username:password@]host[:port][/database][?options]

Common options:

OptionExamplePurpose
authSourceauthSource=adminDatabase used for authentication
replicaSetreplicaSet=rs0Connect to a replica set
tls=truetls=trueEnable TLS/SSL
serverSelectionTimeoutMSserverSelectionTimeoutMS=5000Timeout for server selection

Databases and Collections

MongoDB organises data in a two-level hierarchy:

  • A database groups related collections (similar to an SQL schema or database).
  • A collection holds documents (similar to an SQL table, but schema-free).

Both are created lazily — they come into existence the first time you insert a document. You never run CREATE DATABASE or CREATE TABLE.

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")

# Reference a database (not yet created on disk)
db = client["mystore"]

# Reference a collection inside it (also not yet on disk)
products = db["products"]

# The database and collection are created when the first document is inserted

Basic CRUD Operations

The following examples build on each other. Run them in order if you are following along interactively.

Create — insert documents

Use insert_one() for a single document and insert_many() for a batch:

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db = client["mystore"]
products = db["products"]

# Insert a single document
result = products.insert_one({
    "name": "Laptop",
    "brand": "Acme",
    "price": 999.99,
    "in_stock": True
})
print("Inserted id:", result.inserted_id)

# Insert multiple documents at once
new_products = [
    {"name": "Mouse",    "brand": "Acme", "price": 29.99,  "in_stock": True},
    {"name": "Keyboard", "brand": "Acme", "price": 79.99,  "in_stock": False},
    {"name": "Monitor",  "brand": "Zeta", "price": 349.99, "in_stock": True},
]
batch_result = products.insert_many(new_products)
print("Inserted ids:", batch_result.inserted_ids)

MongoDB automatically adds an _id field (of type ObjectId) to every document if you do not supply one. This field is the primary key and is always unique within a collection.

Read — query documents

find_one() returns the first matching document (or None). find() returns a cursor you can iterate over.

# Retrieve one document (no filter = the first document in natural order)
doc = products.find_one()
print(doc)

# Retrieve all documents in the collection
for p in products.find():
    print(p["name"], "-", p["price"])

# Filter: products that are in stock
for p in products.find({"in_stock": True}):
    print(p["name"])

# Projection: return only name and price (exclude _id)
for p in products.find({}, {"_id": 0, "name": 1, "price": 1}):
    print(p)

Query operators

MongoDB's query language uses operators prefixed with $:

# Products cheaper than £100
cheap = products.find({"price": {"$lt": 100}})

# In-stock products from brand "Acme" or "Zeta"
multi = products.find({
    "in_stock": True,
    "brand": {"$in": ["Acme", "Zeta"]}
})

# Price between 50 and 500 (inclusive)
range_q = products.find({"price": {"$gte": 50, "$lte": 500}})

Common comparison operators:

OperatorMeaning
$eqEqual (default when using {"field": value})
$neNot equal
$gt / $gteGreater than / greater than or equal
$lt / $lteLess than / less than or equal
$inValue is in a list
$ninValue is not in a list

Update — modify documents

update_one() modifies the first matching document. update_many() modifies all matches. Always use a $set operator to change specific fields — without it you replace the entire document.

# Update a single document: change the price of "Mouse"
update_result = products.update_one(
    {"name": "Mouse"},          # filter
    {"$set": {"price": 24.99}}  # update
)
print("Matched:", update_result.matched_count,
      "Modified:", update_result.modified_count)

# Mark all Acme products as in stock
products.update_many(
    {"brand": "Acme"},
    {"$set": {"in_stock": True}}
)

# Increment a field value
products.update_one(
    {"name": "Laptop"},
    {"$inc": {"price": -50}}  # reduce price by 50
)

Common update operators:

OperatorEffect
$setSet one or more fields
$unsetRemove a field
$incIncrement a numeric field
$pushAppend a value to an array field
$pullRemove a value from an array field

Delete — remove documents

delete_one() removes the first matching document. delete_many() removes all matches.

# Remove a single document
del_result = products.delete_one({"name": "Keyboard"})
print("Deleted count:", del_result.deleted_count)

# Remove all out-of-stock items
products.delete_many({"in_stock": False})

# Confirm what is left
print("Remaining products:")
for p in products.find({}, {"_id": 0, "name": 1}):
    print(" -", p["name"])

Common Gotchas

Lazy creation can hide typos

Because MongoDB creates databases and collections on demand, a typo silently creates a second, empty database instead of raising an error:

# Intended: client["mystore"]   Actual: client["mystoree"]
db = client["mystoree"]  # no error, but your data goes to the wrong database

Fix: define database and collection names as module-level constants:

DB_NAME  = "mystore"
COL_NAME = "products"

db = client[DB_NAME]
products = db[COL_NAME]

Connection errors surface only on first operation

MongoClient() succeeds even when MongoDB is not running. The error appears only when you make an actual request. Use serverSelectionTimeoutMS and a ping check at startup (as shown in the connection section above) to fail fast.

Missing $set replaces the entire document

# WRONG — replaces the whole document with just {"price": 24.99}
products.update_one({"name": "Mouse"}, {"price": 24.99})

# CORRECT — only changes the price field
products.update_one({"name": "Mouse"}, {"$set": {"price": 24.99}})

find() returns a cursor, not a list

A cursor is lazy — documents are fetched from the server only as you iterate. If you need a plain list, convert it explicitly:

all_products = list(products.find())

Be careful with large collections: fetching everything into memory at once can exhaust RAM.

What is Next

This chapter covered the essentials. The rest of the Python MongoDB series goes deeper on each topic:

Was this page helpful?