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.

  1. Go to https://www.mongodb.com/cloud/atlas
  2. Click Try Free and sign in with Google or your email address.
  3. Choose Shared (Free) cluster and select a region (for example, Frankfurt - AWS).
  4. Create a new database, for example workshop, and a collection called products.
  5. 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.


This site uses Just the Docs, a documentation theme for Jekyll.