MongoDB Academy · Lektion

Kravanalys och schemadesign

Ni kommer att översätta applikationskrav till ett MongoDB-schema, välja mellan inbäddning och referenser samt tillämpa designmönster på lämpligt sätt.

Lektion 1 av 413 steg

Kravanalys och schemadesign är en gratis lektion i MongoDB Academy på CoddyKit. Detta är lektion 1 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för MongoDB Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i MongoDB Academy innehåller totalt 4 lektioner.

Slutprojektet: utforma en riktig applikation

I den här slutprojektlektionen använder du all kunskap från MongoDB-spåret för att utforma en produktionsklar applikation från grunden. Vi bygger en e-handelsplattform med flera säljare – en domän som är tillräckligt omfattande för att pröva beslut om inbäddning kontra referenser, indexplanering, aggregationsdesign och säkerhet. Processen börjar med kravanalys, som styr alla efterföljande beslut om schemat.

Steg 1: samla in funktionella krav

Börja med att lista applikationens centrala entiteter och operationer. För vår e-handelsplattform: entiteter – Users, Vendors, Products, Orders, Reviews, Carts; operationer – bläddra bland produkter efter kategori, sök med nyckelord, lägg beställningar, behandla betalningar, spåra leveranser och skriv recensioner. Varje operation motsvarar en eller flera MongoDB-frågor, och dessa frågor styr beslut om schemat.

// Requirement analysis output (pseudocode spec)
const requirements = {
  reads: [
    'Get product by slug (very high frequency)',
    'List products by category + sort/filter (high frequency)',
    'Search products by keyword (high frequency)',
    'Get order history for a user (medium frequency)',
    'Get order detail (medium frequency)'
  ],
  writes: [
    'Create order (medium frequency)',
    'Update order status (medium frequency)',
    'Add product review (low frequency)',
    'Update product inventory (high frequency)'
  ]
}

Steg 2: identifiera åtkomstmönster

Åtkomstmönster är de specifika frågor som applikationen kommer att köra. Dokumentera dem noggrant innan du utformar schemat – schemat ska anpassas efter frågorna, inte tvärtom. För varje mönster ska du ange: filterfält, sorteringsfält, projicerade fält och uppskattad frekvens. Högfrekventa mönster styr beslut om indexering och inbäddning. Lågfrekventa mönster kan tåla överlagringen från join-operationer eller aggregationspipelines.

// Access pattern register
const accessPatterns = [
  {
    name: 'Product page',
    filter: { slug: 1 },
    projection: 'all except internal fields',
    frequency: 'very high',
    decision: 'index on slug; embed top 5 reviews'
  },
  {
    name: 'Category listing',
    filter: { categoryId: 1, price: 1 },
    sort: { price: 1, createdAt: -1 },
    frequency: 'high',
    decision: 'compound index { categoryId, price, createdAt }'
  }
]

Utforma Products-samlingen

Produktdokumentet är det dokument som läses oftast i systemet. Tillämpa de inlärda mönstren: Computed Pattern för förberäknad statistik (avgRating, reviewCount); Subset Pattern för att bädda in endast de 5 bästa recensionerna; Extended Reference för att bädda in säljarens namn och logotyp tillsammans med vendorId. Detta eliminerar join-operationer för 95 % av renderingarna av produktsidan.

// Product document schema (simplified)
{
  _id: ObjectId(),
  slug: 'wireless-headphones-pro',
  name: 'Wireless Headphones Pro',
  categoryId: ObjectId(),
  vendor: {
    _id: ObjectId(),         // reference for updates
    name: 'AudioTech Ltd',   // Extended Reference
    logoUrl: '...'           // Extended Reference
  },
  price: 149.99,
  stock: 234,
  avgRating: 4.3,           // Computed Pattern
  reviewCount: 892,          // Computed Pattern
  topReviews: [ /* 5 most recent */ ],  // Subset Pattern
  tags: ['audio', 'wireless', 'headphones'],
  schema_version: 1
}

Utforma Orders-samlingen

Beställningar är ett klassiskt snapshot-dokument: de fångar priser och adresser vid köptillfället, inte det aktuella tillståndet. Bädda in hela leveransadressen (inte en referens till användarens aktuella adress), produktsnapshoten (namn, pris och bild vid köptillfället) samt säljarens namn. Då förblir beställningarna korrekta även om priser ändras eller säljare uppdaterar sina profiler.

// Order document schema
{
  _id: ObjectId(),
  userId: ObjectId(),
  status: 'processing',  // 'pending', 'processing', 'shipped', 'delivered', 'refunded'
  createdAt: new Date(),
  shippingAddress: {
    name: 'Alice Smith',
    street: '42 Elm St',
    city: 'Istanbul',
    country: 'TR'
  },
  items: [
    {
      productId: ObjectId(),     // reference for linking
      slug: 'wireless-...',
      name: 'Wireless Headphones Pro',  // snapshot
      price: 149.99,             // price at purchase time
      quantity: 1,
      imageUrl: '...'
    }
  ],
  subtotal: 149.99,
  tax: 27.00,
  total: 176.99
}

Tillämpa beslutsramverket för schemadesign

För varje relation tillämpar du följande checklista: Hur ofta används den tillsammans med den andra datan? (bädda in om alltid, använd referens om sällan); Hur ofta ändras den refererade datan? (bädda in om sällan, använd referens om ofta); Kommer den inbäddade arrayen att växa utan gräns? (använd referens om ja, bädda in om den är begränsad); Frågas datan efter självständigt? (separat samling om ja, bädda in om den alltid nås via överordnad data).

// Decision table for our e-commerce schema
const decisions = [
  { entity: 'Order items',       decision: 'embed',     reason: 'always fetched with order; price snapshot required' },
  { entity: 'Shipping address',  decision: 'embed',     reason: 'snapshot at purchase time; changes do not affect order' },
  { entity: 'Product reviews',   decision: 'separate + subset', reason: 'grows unbounded; top-5 subset in product doc' },
  { entity: 'Vendor details',    decision: 'extended ref', reason: 'name/logo read on every product page; changes rarely' },
  { entity: 'Category tree',     decision: 'separate',  reason: 'queried independently; used for breadcrumbs' }
]

Schemavalidering för kritiska samlingar

Lägg till JSON Schema-validatorer för samlingarna products och orders för att förhindra att felaktigt utformade dokument förstör dina data. Kräv obligatoriska fält (price måste vara ett positivt tal och status måste vara ett av de giltiga enum-värdena) och ange validationAction: 'error' för att avvisa ogiltiga skrivningar direkt i stället för att bara utfärda en varning.

db.runCommand({
  collMod: 'orders',
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['userId', 'status', 'items', 'total', 'createdAt'],
      properties: {
        status: {
          bsonType: 'string',
          enum: ['pending', 'processing', 'shipped', 'delivered', 'refunded']
        },
        total: { bsonType: 'double', minimum: 0 },
        items: { bsonType: 'array', minItems: 1 }
      }
    }
  },
  validationAction: 'error'
})

Planera indexuppsättningen

Definiera index för alla högfrekventa åtkomstmönster. Använd ESR-regeln (Equality → Sort → Range) för sammansatta index. Skapa bara index för frågor med hög frekvens – oanvända index försämrar skrivprestandan och slösar RAM. Dokumentera syftet med varje index så att teamet kan ta bort överflödiga index när åtkomstmönstren utvecklas.

// Products collection indexes
db.products.createIndex({ slug: 1 }, { unique: true })  // product page lookup
db.products.createIndex({ categoryId: 1, price: 1, _id: 1 })  // category listing + keyset pagination
db.products.createIndex({ tags: 1 })  // tag filter
db.products.createIndex({ 'vendor._id': 1 })  // vendor store page

// Orders collection indexes
db.orders.createIndex({ userId: 1, createdAt: -1 })  // user order history
db.orders.createIndex({ status: 1, createdAt: 1 })   // fulfillment queue

Hantera samtidiga lageruppdateringar

En kritisk utmaning inom e-handel är att förhindra överförsäljning: två användare ska inte båda kunna köpa den sista varan i lager. Använd MongoDB:s atomära findOneAndUpdate med villkoret stock: { $gt: 0 }. Uppdateringen lyckas endast om varan finns i lager, och minskningen är atomär – ingen race condition är möjlig.

// Atomically reserve stock — returns null if out of stock
const product = await db.collection('products').findOneAndUpdate(
  { _id: productId, stock: { $gte: quantity } },  // guard: enough stock
  { $inc: { stock: -quantity } },
  { returnDocument: 'after', projection: { stock: 1, name: 1, price: 1 } }
)

if (!product) {
  throw new Error('Insufficient stock')
}
// Proceed to create order with product snapshot

Aggregationspipeline för rapportering

Utforma en aggregationspipeline för en försäljningssammanfattning som rapporterar intäkter per säljare under de senaste 30 dagarna. Detta är ett klassiskt fall där aggregationspipen ersätter komplex beräkning på applikationssidan. Pipen matchar aktuella beställningar, packar upp artiklar, grupperar efter säljare och sorterar efter totala intäkter.

// Revenue by vendor, last 30 days
const since = new Date(Date.now() - 30 * 86400000)

db.orders.aggregate([
  { $match: { status: 'delivered', createdAt: { $gte: since } } },
  { $unwind: '$items' },
  {
    $group: {
      _id: '$items.vendorId',
      totalRevenue: { $sum: { $multiply: ['$items.price', '$items.quantity'] } },
      orderCount: { $addToSet: '$_id' }
    }
  },
  { $addFields: { orderCount: { $size: '$orderCount' } } },
  { $sort: { totalRevenue: -1 } },
  { $limit: 20 }
])

Testa schemat med explain()

Innan du går till produktion ska du validera varje kritisk fråga med explain('executionStats'). Kontrollera att alla högfrekventa frågor visar IXSCAN (inte COLLSCAN) i den vinnande planen, att docsExamined ligger nära nReturned och att totalKeysExamined är rimligt. Alla frågor som visar COLLSCAN eller har ett högt förhållande mellan docsExamined och nReturned behöver ett index.

// Validate the category listing query
const stats = db.products.find(
  { categoryId: ObjectId('...'), price: { $lte: 200 } }
).sort({ price: 1 }).explain('executionStats')

const plan = stats.executionStats
console.log('Stage:', plan.executionStages.inputStage.stage)  // should be IXSCAN
console.log('Keys examined:', plan.totalKeysExamined)          // should be small
console.log('Docs examined:', plan.totalDocsExamined)          // should equal nReturned
console.log('Docs returned:', plan.nReturned)

Snabbtest

Testa dina kunskaper om begreppen MongoDB & NoSQL Databases från den här lektionen.

Sammanfattning av lektionen

I den här lektionen lärde du dig: kravanalys och dokumentation av åtkomstmönster kommer före schemadesign – schemat ska anpassas efter frågorna, inte tvärtom, ett bra produktdokument kombinerar Extended Reference, Computed Pattern och Subset Pattern för att eliminera join-operationer i den frekventa läsvägen, och atomisk findOneAndUpdate med skyddsvillkor förhindrar överförsäljning utan att transaktioner krävs. Härnäst definierar vi indexstrategin och validerar varje index med explain().

Gratis att börja

Lär dig JavaScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
30
Lektioner
120

Vanliga frågor

Är lektionen ”Kravanalys och schemadesign” gratis?

Ja – hela texten till ”Kravanalys och schemadesign” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i MongoDB Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i MongoDB Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Kravanalys och schemadesign”?

Ni kommer att översätta applikationskrav till ett MongoDB-schema, välja mellan inbäddning och referenser samt tillämpa designmönster på lämpligt sätt. Ni övar på MongoDB Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig MongoDB Academy?

Du behöver inga förkunskaper. Utbildningen i MongoDB Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.

Hur lång tid tar lektionen ”Kravanalys och schemadesign”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här MongoDB Academy-lektionen?

Ja. Varje MongoDB Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Kravanalys och schemadesign
  2. Indexstrategi och validering av frågeplaneraren
  3. Skalningsplan: från replikuppsättning till sharded-kluster
  4. Säkerhetshärdning och checklista för produktion
← Tillbaka till MongoDB Academy