Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

MongoDB Relationships One to Many $lookup: Tutorial, Examples, FAQs & Interview Tips

Modelling Relationships in MongoDB

MongoDB supports two primary strategies for representing relationships: embedding (denormalization) and referencing (normalization). Unlike SQL, there are no foreign key constraints - you manage relationships in application logic or through the aggregation pipeline.

Embedded Documents

One-to-One and One-to-Many Embedded
// ONE-TO-ONE EMBEDDED: User with address
{
  "_id": ObjectId("u1"),
  "name": "Alice Johnson",
  "address": { "street": "123 Main St", "city": "New York", "zip": "10001" }
}

// ONE-TO-MANY EMBEDDED: Post with comments (bounded array)
{
  "_id": ObjectId("p1"),
  "title": "Getting Started with MongoDB",
  "comments": [
    { "user": "Bob",   "text": "Great article!", "date": ISODate("2024-01-10") },
    { "user": "Carol", "text": "Very helpful.",   "date": ISODate("2024-01-11") }
  ]
}

// Query embedded field
db.posts.find({ "comments.user": "Bob" })

// Update embedded array element using positional operator
db.posts.updateOne(
  { _id: ObjectId("p1"), "comments.user": "Bob" },
  { $set: { "comments.$.text": "Updated comment!" } }
)

Manual References

One-to-Many Referenced with $lookup
// users collection
{ "_id": ObjectId("u1"), "name": "Alice Johnson", "email": "alice@example.com" }

// orders collection - each order references the user
{ "_id": ObjectId("o1"), "userId": ObjectId("u1"), "total": 1299.99, "status": "shipped" }
{ "_id": ObjectId("o2"), "userId": ObjectId("u1"), "total": 45.00,   "status": "pending" }

// Join using $lookup aggregation
db.users.aggregate([
  { $match: { _id: ObjectId("u1") } },
  { $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "userId",
      as: "orders"
  }},
  { $project: { name: 1, email: 1, orderCount: { $size: "$orders" }, orders: 1 } }
])

Many-to-Many Relationships

Many-to-Many with Arrays of References
// Students and Courses - many-to-many
// students collection
{
  "_id": ObjectId("s1"),
  "name": "Bob Smith",
  "enrolledCourses": [ObjectId("c1"), ObjectId("c2")]
}

// courses collection
{
  "_id": ObjectId("c1"),
  "title": "MongoDB Fundamentals",
  "enrolledStudents": [ObjectId("s1"), ObjectId("s2")]
}

// Find all courses a student is enrolled in
db.courses.find({ _id: { $in: [ObjectId("c1"), ObjectId("c2")] } })

// Add a student to a course
db.courses.updateOne(
  { _id: ObjectId("c1") },
  { $addToSet: { enrolledStudents: ObjectId("s3") } }
)
db.students.updateOne(
  { _id: ObjectId("s3") },
  { $addToSet: { enrolledCourses: ObjectId("c1") } }
)
Embed vs Reference Decision Guide
// EMBED when:
// - Data is always accessed together with the parent
// - The sub-document is small and bounded (e.g., max 10-20 items)
// - The sub-document is not shared across multiple parents
// - You want atomic reads/writes in a single operation

// REFERENCE when:
// - Data is accessed independently of the parent
// - The array could grow unboundedly (e.g., all comments on a viral post)
// - The same data is referenced by multiple documents
// - The sub-document is large and rarely needed

// Example: User profile - EMBED (always needed together)
{ "_id": ObjectId("u1"), "name": "Alice", "profile": { "bio": "...", "avatar": "..." } }

// Example: User orders - REFERENCE (many orders, accessed separately)
// orders: { userId: ObjectId("u1"), total: 99.99, ... }
// db.orders.find({ userId: ObjectId("u1") })

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.