MongoDB Academy · Lektion

Bedste praksis for projektioner i API-svar

Design projektioner, der stemmer overens med REST API-svars struktur, så payload-størrelsen reduceres, og følsomme felter beskyttes.

Lektion 4 af 413 trin

Bedste praksis for projektioner i API-svar er en gratis MongoDB Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i MongoDB Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. MongoDB Academy-kurset indeholder 4 lektioner i alt.

Tilpas projektioner til API-svarets struktur

Hvert REST- eller GraphQL-endepunkt, som din applikation eksponerer, har en defineret struktur for svaret. Den ideelle MongoDB-projektion returnerer præcis de felter, som denne struktur kræver – hverken flere eller færre. Når din projektion afspejler kontrakten for dit API-svar, undgår du to almindelige antipatterns: overhentning (felter, som endepunktet aldrig sender) og underhentning (felter, der tvinger dig til at udføre en ekstra forespørgsel).

Definér projektionskonstanter

Hvis du hardkoder projektionsobjekter direkte i hver forespørgsel, fører det med tiden til gentagelser og afvigelser. Definér projektionskonstanter sammen med dine dataadgangsfunktioner eller repositories. Hvis strukturen for API-svaret ændrer sig, skal du kun opdatere én konstant i stedet for at lede efter alle forespørgsler i kodebasen.

// projections.js — centralised projection definitions
export const USER_PUBLIC = { _id: 0, username: 1, avatarUrl: 1, createdAt: 1 };
export const USER_PROFILE = { _id: 0, username: 1, email: 1, bio: 1, avatarUrl: 1 };
export const USER_ADMIN = { _id: 0, username: 1, email: 1, role: 1, lastLoginAt: 1, isActive: 1 };

// Usage
const user = await db.collection('users').findOne({ username: 'alice' }, { projection: USER_PROFILE });

Returnér aldrig følsomme felter til klienter

Felter som passwordHash, totpSecret, apiKey, ssn og paymentMethodToken må aldrig forekomme i API-svar. Definér en sikker grundprojektion, der som standard udelukker dem, og hent dem kun i interne servicekald, der specifikt har brug for dem. Anvend princippet om mindst mulige rettigheder på datalaget.

// Always exclude sensitive fields from user queries
const SECURE_USER_BASE = {
  passwordHash: 0,
  totpSecret: 0,
  resetToken: 0
};

// All user API responses go through this projection
const user = await db.collection('users').findOne(
  { _id: userId },
  { projection: SECURE_USER_BASE }
);

// Result never contains passwordHash or totpSecret

Listeendepunkter: Projicér kun opsummeringsfelter

Listeendepunkter (f.eks. GET /products) returnerer typisk en opsummering af hvert element og ikke hele dokumentet. En produktliste viser måske name, price, thumbnailUrl og rating – ikke den fulde description, arrayet specifications eller reviews. En begrænset projektion til listeforespørgsler kan reducere størrelsen på nyttedataene med 90 %, når fulde dokumenter indeholder store tekstmængder eller arrays.

const PRODUCT_SUMMARY = {
  _id: 0,
  slug: 1,
  name: 1,
  price: 1,
  thumbnailUrl: 1,
  rating: 1,
  reviewCount: 1
};

// GET /products — lightweight list query
const products = await db.collection('products')
  .find({ category: 'electronics', isActive: true })
  .projection(PRODUCT_SUMMARY)
  .sort({ rating: -1 })
  .limit(20)
  .toArray();

Detaljeendepunkter: Projicér hele objektet

Detaljeendepunkter (f.eks. GET /products/:slug) returnerer en mere omfattende visning af et enkelt dokument. Selv her bør du overveje at udelukke felter, der kun er interne. Du kan projicere alle offentlige felter, men undertrykke intern kostpris, leverandørens kontaktoplysninger eller ID'er fra lagerets kildesystem, som klienter ikke bør se.

const PRODUCT_DETAIL = {
  supplierCost: 0,       // internal — never expose to clients
  warehouseLocation: 0,  // internal
  syncedFromErpAt: 0     // internal audit field
};

// GET /products/:slug — rich detail query
const product = await db.collection('products').findOne(
  { slug: req.params.slug, isActive: true },
  { projection: PRODUCT_DETAIL }
);

Brug også projektioner i aggregeringspipelines

Bedste praksis for projektioner gælder også for aggregeringspipelines. Placér et trin med $project efter $match og før dyre trin som $lookup eller $unwind for at reducere størrelsen på de dokumenter, der bevæger sig gennem pipelinen. Mindre dokumenter i pipelinen betyder mindre brug af hukommelse og CPU på serveren.

db.orders.aggregate([
  { $match: { status: 'shipped', customerId: ObjectId('c1') } },
  // Project early to reduce document size before $lookup
  { $project: { total: 1, createdAt: 1, customerId: 1, _id: 0 } },
  {
    $lookup: {
      from: 'customers',
      localField: 'customerId',
      foreignField: '_id',
      as: 'customer'
    }
  }
]);

Projektioner og API-versionering

Når du føjer nye felter til MongoDB-dokumenter, forventer ældre API-klienter dem måske ikke. Ved at bruge strikte inklusionsprojektioner (hvor du angiver præcis de felter, der skal returneres) bliver nye dokumentfelter usynlige for eksisterende API-forbrugere, indtil du udtrykkeligt føjer dem til projektionen. Det giver en naturlig versionsgrænse: Opdatér projektionen, når du opdaterer API-versionen.

// v1 projection — stable contract for existing clients
export const USER_V1 = { _id: 0, username: 1, email: 1 };

// v2 projection — includes new avatarUrl and bio fields
export const USER_V2 = { _id: 0, username: 1, email: 1, avatarUrl: 1, bio: 1 };

Test, at projektioner stemmer overens med svarskemaer

Skriv enhedstests, der kontrollerer, at MongoDB-projektionsobjektet stemmer overens med dit API-svarskema (f.eks. et Joi-skema eller en TypeScript-type). Det forhindrer den almindelige fejl, hvor en udvikler føjer et felt til API-svartypen, men glemmer at inkludere det i projektionen – feltet kommer tilbage som undefined i produktion, selv om TypeScript-typekontrollen godkender det.

// Example test asserting projection covers all required response fields
const USER_RESPONSE_FIELDS = ['username', 'email', 'avatarUrl'];
const projection = { username: 1, email: 1, avatarUrl: 1, _id: 0 };

for (const field of USER_RESPONSE_FIELDS) {
  if (projection[field] !== 1) {
    throw new Error('Projection missing field: ' + field);
  }
}
console.log('Projection covers all required response fields');

Undgå uoverensstemmelser i projektioner med Mongoose

Mongoose-skemaer med select: false på et felt forhindrer, at feltet vises i et forespørgselsresultat, medmindre det udtrykkeligt inkluderes igen. Kombinér dette med virtuelle felter på skemaniveau for at beregne afledte værdier uden at gemme dem. Tilsammen gør disse værktøjer det muligt at håndhæve en sikker standardprojektion på modelniveau og dermed mindske risikoen for utilsigtet datalækage på grund af en manglende forespørgselsprojektion.

const userSchema = new mongoose.Schema({
  username: String,
  email:    String,
  // Excluded from all queries by default — must explicitly use +passwordHash
  passwordHash: { type: String, select: false },

  // Virtual — computed, not stored, never in DB
  get displayName() { return this.username.toUpperCase(); }
});
userSchema.virtual('displayName').get(function() {
  return this.username.toUpperCase();
});

Overvåg projektionernes effektivitet

Brug explain('executionStats')

for at kontrollere, at dine projektioner fungerer som forventet. Se på forholdet mellem nReturned og keysExamined samt docsExamined. Hvis docsExamined er lig med antallet af matchede dokumenter (og ikke nul), er din projektion ikke dækket af et indeks, men den er stadig korrekt – du kan vurdere, om det er vedligeholdelsesomkostningen værd at tilføje et dækkende indeks.

const result = await db.collection('users').find(
  { role: 'admin' },
  { projection: { username: 1, email: 1, _id: 0 } }
).explain('executionStats');

console.log('Docs examined:', result.executionStats.totalDocsExamined);
console.log('Keys examined:', result.executionStats.totalKeysExamined);
console.log('Docs returned:', result.executionStats.nReturned);

Opsummering: Tjekliste til bedste praksis for projektioner

Brug denne tjekliste til alle MongoDB-forespørgsler i dit API:

  • Definér navngivne projektionskonstanter – én pr. endepunkt eller struktur for svaret
  • Brug inklusionstilstand til API-svar – angiv præcis det, du har brug for
  • Udeluk altid følsomme felter – passwordHash, tokens og interne ID'er
  • Brug begrænsede projektioner til listeendepunkter – kun opsummeringer, ingen store brødtekster
  • Placér $project tidligt i aggregeringspipelines – reducér de data, der føres videre

Hurtig kontrol

Test din forståelse af begreberne MongoDB og NoSQL Databases fra denne lektion.

Opsummering af lektionen

I denne lektion har du lært, at projektionskonstanter bør defineres pr. API-endepunkt for at forhindre afvigelser, at følsomme felter altid skal udelukkes fra forespørgsler, der er rettet mod klienter, og at en tidlig placering af $project i aggregeringspipelines reducerer belastningen på hukommelsen. Næste emne er sortering og sideinddeling, så du effektivt kan ordne og inddele store resultatsæt.

Gratis at komme i gang

Lær JavaScript med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
30
Lektioner
120

Ofte stillede spørgsmål

Er lektionen “Bedste praksis for projektioner i API-svar” gratis?

Ja — hele teksten til “Bedste praksis for projektioner i API-svar” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af MongoDB Academy-kurset, skal du opgradere til CoddyKit PRO. MongoDB Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Bedste praksis for projektioner i API-svar”?

Design projektioner, der stemmer overens med REST API-svars struktur, så payload-størrelsen reduceres, og følsomme felter beskyttes. Du øver dig i MongoDB Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på MongoDB Academy?

Der kræves ingen tidligere erfaring. MongoDB Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Bedste praksis for projektioner i API-svar”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne MongoDB Academy-lektion?

Ja. Alle MongoDB Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Inkluderings- og ekskluderingsprojektioner
  2. Projektion af indlejrede felter og arrays
  3. Arrayprojektionerne $ og $elemMatch
  4. Bedste praksis for projektioner i API-svar
← Tilbage til MongoDB Academy