Working with Documents
In this section, you will learn how to store, query, and modify data in a document database using MongoDB.
Documents are stored as JSON-like objects (BSON), and queries are written in JavaScript-like syntax.
Setting up MongoDB
To practice with MongoDB, you can either set up an instance in an online cloud environment or run it locally using a Docker container.
Getting started with MongoDB Atlas
Before writing queries, you can use MongoDB Atlas — a free online cloud environment.
- Go to https://www.mongodb.com/cloud/atlas
- Click Try Free and sign in with Google or your email address.
- Choose Shared (Free) cluster and select a region (for example, Frankfurt - AWS).
- Create a new database, for example
workshop, and a collection calledproducts. - Open Atlas Data Explorer or Atlas Shell to start writing queries.
You can now enter commands in the Atlas Shell, starting with:
use workshop
and then interacting with your collection:
db.products.find()
Running MongoDB locally with Docker
Prerequisites
- Docker installed on your system
- Basic command-line knowledge
Step 1: Pull the MongoDB Docker Image
For most systems, use the latest MongoDB Community Server image:
docker pull mongodb/mongodb-community-server:latest
However, MongoDB 5+ requires a CPU instruction (AVX) that is not available in Oracle VM VirtualBox. If you’re using Oracle VM and encounter an error like:
Error code -4: Could not initialise
Then use this compatible version instead:
docker pull mongodb/mongodb-community-server:4.4.3-ubuntu2004-20230514T053842Z
Step 2: Run the MongoDB Container:
Use the following command to start MongoDB:
docker run -d \
--name mongodb \
mongodb/mongodb-community-server:latest
If you’re using Oracle VM, replace latest with:
4.4.3-ubuntu2004-20230514T053842Z
Step 3: Connect with the MongoDB:
You can now connect to the MongoDB shell with:
docker exec -it mongodb mongo
Create a database ‘workshop’ and a collection ‘products’
use workshop
db.createCollection("products")
Inserting documents
Documents in MongoDB are stored inside collections (similar to tables in relational databases).
Insert a single document
db.products.insertOne({
name: "Laptop",
brand: "Lenovo",
price: 899,
stock: 25,
specs: { RAM: 16, storage: 512 }
})
Insert multiple documents
db.products.insertMany([
{ name: "Smartphone", brand: "Samsung", price: 699, stock: 50, specs: { RAM: 8, storage: 256 } },
{ name: "Tablet", brand: "Apple", price: 799, stock: 15, specs: { RAM: 6, storage: 128 } },
{ name: "Monitor", brand: "Dell", price: 299, stock: 40, specs: { size: 27 } }
])
Explanation of ObjectId()
After inserting a document, MongoDB returns an insertedId, which is an ObjectId. This is automatically generated unless you provide your own _id.
{
"acknowledged" : true,
"insertedId" : ObjectId("690377ec665660507ba6552e")
}
In MongoDB every document has an _id property that uniquely identifies the document in the collection. If you don’t provide a value for _id, MongoDB will automatically generate one using the ObjectId() function. An ObjectId is a 12 byte hexadecimal value, which consists of:
- 4 bytes: timestamp of creation
- 5 bytes: machine and process-id
- 3 bytes: incremental number
This structure ensures that each document has a unique identifier. While ObjectId is commonly used as a primary key, it is not a natural key like a username or product code — it is a surrogate key generated by the system.
You can also assign your own _id values using strings, integers, or other BSON types. But then you are responsible for ensuring it is unique within the collection.
Querying documents
Find all documents
db.products.find()
Return only selected fields
Use projection to return specific fields.
db.products.find({}, { name: 1, price: 1, _id: 0 })
Explanation:
- {} → this is the query filter, meaning “find all documents”.
- { name: 1, price: 1, _id: 0 } → this is the projection:
- name: 1 → include the field name in the output
- price: 1 → include the field price in the output
- _id: 0 → exclude the _id field (MongoDB includes _id by default)
As a result, you get only the name and price fields for each product.
You can’t mix inclusion (1) and exclusion (0) in the same projection, except for the _id field. So, this will yield an error:
db.products.find({}, { name: 1, price: 0, _id: 0 })
Filtering results
You can use comparison and logical operators.
// Find all products with price greater than 500
db.products.find({ price: { $gt: 500 } })
// Find all products from specific brands
db.products.find({ brand: { $in: ["Apple", "Samsung"] } })
// Combine multiple conditions
db.products.find({
$and: [
{ price: { $gt: 400 } },
{ stock: { $lte: 30 } }
]
})
Working with nested fields
You can query inside sub-documents using dot notation.
// Find all products with 16 GB RAM
db.products.find({ "specs.RAM": 16 })
Nested structures can represent complex entities such as customer addresses or order details.
db.customers.insertOne({
name: "Alice",
address: { street: "Main St 5", city: "Rotterdam", postal: "3011AB" }
})
// Find customers in Rotterdam
db.customers.find({ "address.city": "Rotterdam" })
Updating documents
Replace fields using $set
db.products.updateOne(
{ name: "Laptop" },
{ $set: { price: 849 } }
)
Increment numeric values using $inc
db.products.updateOne(
{ name: "Laptop" },
{ $inc: { stock: -1 } }
)
Update multiple documents
db.products.updateMany(
{ brand: "Samsung" },
{ $set: { discount: 10 } }
)
Deleting documents
Delete one document
db.products.deleteOne({ name: "Monitor" })
Delete all documents matching a filter
db.products.deleteMany({ brand: "Samsung" })
🧠 Practice Questions
Question 1:
Insert a new product: a “Headphones” with brand “Sony”, price 149, stock 20.
Click to reveal the answer
```javascript db.products.insertOne({ name: "Headphones", brand: "Sony", price: 149, stock: 20 }) ```Question 2:
Find all products with a price between 300 and 800.
Click to reveal the answer
```javascript db.products.find({ price: { $gte: 300, $lte: 800 } }) ```Question 3:
List all products that have at least 8 GB of RAM.
Click to reveal the answer
```javascript db.products.find({ "specs.RAM": { $gte: 8 } }) ```Question 4:
Reduce the stock of all Apple products by 2.
Click to reveal the answer
```javascript db.products.updateMany( { brand: "Apple" }, { $inc: { stock: -2 } } ) ```Question 5:
Delete all products with a price greater than 1000.
Click to reveal the answer
```javascript db.products.deleteMany({ price: { $gt: 1000 } }) ```Summary
MongoDB allows you to store flexible, nested data structures and query them efficiently using JSON-like syntax.
Compared to relational databases, it offers greater flexibility but less enforced structure — making it ideal for evolving datasets, catalogues, and applications where data shape changes over time.