Personal Catalogue: React, Express & MongoDB — Chapter 3, Exercise 2 ===================================================================== TASK Remove .lean() from the GET /api/items route, create a Book item, and confirm via a real request that its author field is missing from the response. Restore .lean() and confirm author reappears. Explain why. SOLUTION Temporarily change the list route to drop .lean(): router.get('/', async (req, res) => { const items = await Item.find(); // .lean() removed res.json(items); }); Create a Book, then list everything: curl -X POST http://localhost:4000/api/items \ -H "Content-Type: application/json" \ -d '{"itemType":"Book","title":"Dune","author":"Frank Herbert"}' curl http://localhost:4000/api/items Output (without .lean()): [{"_id":"...","title":"Dune","releaseYear":null,"notes":null, "itemType":"Book","createdAt":"...","updatedAt":"..."}] The author field is genuinely absent — not null, not empty, just not present in the object at all — even though it was stored successfully (a direct GET /api/items/ through the Book model, or inspecting the document in mongosh, confirms author is really there in the database). Restore .lean(): router.get('/', async (req, res) => { const items = await Item.find().lean(); res.json(items); }); Output (with .lean() restored, same document, same request): [{"_id":"...","title":"Dune","releaseYear":null,"notes":null, "itemType":"Book","author":"Frank Herbert","createdAt":"...", "updatedAt":"..."}] author is back, with no other change to the route. WHY THIS HAPPENS ----------------- Without .lean(), Item.find() returns real Mongoose documents hydrated against Item's own schema. Hydration only attaches the paths a schema actually defines, and author isn't one of Item's own paths — it only exists on Book's discriminator schema. Serializing that hydrated document to JSON (via res.json(), which calls toJSON() internally) reflects only the paths Item's schema recognizes, so author is silently dropped from the response even though the raw stored document still has it. .lean() skips hydration entirely. It returns a plain JavaScript object built directly from whatever MongoDB actually sent back over the wire, with no schema-based filtering applied at any point — so every field the document genuinely has, regardless of which discriminator's schema it belongs to, comes through untouched. WHY THIS WORKS AS AN ANSWER ---------------------------- It reproduces the exact failure Chapter 2's warn-box predicted with a real request and a real, observed missing field, confirms the data was never actually lost (only hidden from this specific query), and explains the real mechanism — hydration versus a plain lean object — rather than describing .lean() as a general "performance" flag, which would miss the actual reason it matters here.