Skip to content

Common Mistakes

Overusing $lookup and Poor Schema Design

Joining collections the application should have modelled differently.

AdvancedAbout 6 minutes

Problem. Every request $lookups three collections because the SQL diagram became collections 1:1. Or line items live in order_items so the order page joins.

db.orders.aggregate([
  { $lookup: { from: "order_items", localField: "_id", foreignField: "orderId", as: "items" } },
  { $lookup: { from: "users", localField: "userId", foreignField: "_id", as: "user" } },
  { $lookup: { from: "products", localField: "items.productId", foreignField: "_id", as: "products" } }
])
Bad — join for data that is the order
{
  userId: ObjectId("64a1b2c3d4e5f6a7b8c90001"),
  amount: 4900,
  items: [
    { name: "Mechanical Keyboard", quantity: 1, unitPrice: 4500 }
  ]
}

db.orders.find({ userId })  // history: no lookup
db.users.aggregate([
  { $match: { city: "Pune" } },
  { $lookup: { from: "orders", localField: "_id", foreignField: "userId", as: "orders" } }
])  // report: match first, then join
Better — embed lines; snapshot name and price; lookup only when you must

$lookup after $limit of 3 is fine. $lookup on the whole orders collection to decorate a list is a schema smell. Populate in Mongoose is the same join with friendlier syntax — still not free.

Interview question

When is $lookup a sign the schema is wrong?

Think about it first.

Practice

A justified lookup, and embedded items you unwind instead of joining.