MongoDB - Pytania Rekrutacyjne dla Backend Developera [2026]

Sławomir Plamowski 11 min czytania
backend database mongodb mongoose nodejs nosql

MongoDB to najpopularniejsza dokumentowa baza danych NoSQL. Jeśli przygotowujesz się do rozmowy na stanowisko Backend Developer, ten przewodnik zawiera 44 pytania rekrutacyjne z odpowiedziami - od CRUD po agregacje i modelowanie danych.

Spis treści


Podstawy MongoDB

Czym jest MongoDB i czym różni się od relacyjnych baz danych?

Odpowiedź w 30 sekund: MongoDB to dokumentowa baza danych NoSQL przechowująca dane w elastycznych dokumentach JSON-like (BSON). W przeciwieństwie do SQL nie wymaga sztywnego schematu, obsługuje zagnieżdżone struktury danych i skaluje się horyzontalnie przez sharding.

Odpowiedź w 2 minuty:

Porównanie MongoDB z relacyjnymi bazami danych przedstawia następująca tabela:

Cecha MongoDB (NoSQL) SQL (relacyjne)
Model danych Dokumenty (BSON) Tabele i wiersze
Schemat Elastyczny Sztywny
Relacje Embedding/Referencing JOIN
Skalowanie Horyzontalne (sharding) Wertykalne
Transakcje Od v4.0 (multi-doc) Pełne ACID
Zapytania MQL (MongoDB Query) SQL

Kiedy MongoDB:

  • Dane mają zmienną strukturę
  • Potrzeba szybkiego prototypowania
  • Duże ilości danych do zapisu
  • Dane hierarchiczne/zagnieżdżone

Kiedy SQL:

  • Złożone relacje między danymi
  • Transakcje krytyczne (finanse)
  • Raportowanie i analityka
  • Dane wymagają spójności
// Dokument MongoDB
{
  _id: ObjectId("507f1f77bcf86cd799439011"),
  name: "Jan Kowalski",
  email: "jan@example.com",
  address: {
    city: "Warszawa",
    street: "Marszałkowska 1"
  },
  orders: [
    { product: "Laptop", price: 3000 },
    { product: "Mouse", price: 50 }
  ]
}

Czym jest BSON i czym różni się od JSON?

Odpowiedź w 30 sekund: BSON (Binary JSON) to binarny format serializacji używany przez MongoDB. Rozszerza JSON o dodatkowe typy danych (Date, ObjectId, Binary, Decimal128) i jest zoptymalizowany pod kątem szybkości parsowania i rozmiaru. JSON jest tekstowy, BSON binarny.

Odpowiedź w 2 minuty:

Główne różnice między JSON a BSON przedstawia poniższa tabela:

Cecha JSON BSON
Format Tekstowy Binarny
Typy danych 6 (string, number, bool, null, array, object) 20+ (+ Date, ObjectId, Binary, itp.)
Parsowanie Wolniejsze Szybsze
Rozmiar Mniejszy dla prostych danych Może być większy (metadata)

Dodatkowe typy BSON:

{
  _id: ObjectId("507f1f77bcf86cd799439011"),  // 12-byte unique ID
  createdAt: ISODate("2024-01-15T10:30:00Z"), // Date
  price: NumberDecimal("19.99"),              // Decimal128
  data: BinData(0, "base64data"),             // Binary
  count: NumberLong(9999999999)               // 64-bit integer
}

MongoDB automatycznie konwertuje JSON → BSON przy zapisie i BSON → JSON przy odczycie.


Operacje CRUD

Jak wstawiać i wyszukiwać dokumenty w MongoDB?

Odpowiedź w 30 sekund: Insert: insertOne() dla jednego dokumentu, insertMany() dla wielu. Find: find() zwraca kursor, findOne() jeden dokument. Filtrowanie przez obiekt query z operatorami ($eq, $gt, $in, $and, $or).

Odpowiedź w 2 minuty:

Podstawowe operacje wstawiania i wyszukiwania dokumentów przedstawia poniższy kod:

// === INSERT ===
// Jeden dokument
db.users.insertOne({
  name: "Jan Kowalski",
  email: "jan@example.com",
  age: 30
});

// Wiele dokumentów
db.users.insertMany([
  { name: "Anna", email: "anna@example.com", age: 25 },
  { name: "Piotr", email: "piotr@example.com", age: 35 }
]);

// === FIND ===
// Wszystkie dokumenty
db.users.find();

// Z filtrem
db.users.find({ age: 30 });

// Jeden dokument
db.users.findOne({ email: "jan@example.com" });

// === OPERATORY PORÓWNANIA ===
db.users.find({ age: { $gt: 25 } });        // age > 25
db.users.find({ age: { $gte: 25, $lte: 35 } }); // 25 <= age <= 35
db.users.find({ name: { $in: ["Jan", "Anna"] } }); // name IN [...]
db.users.find({ email: { $ne: null } });    // email != null

// === OPERATORY LOGICZNE ===
db.users.find({
  $and: [
    { age: { $gte: 25 } },
    { email: { $exists: true } }
  ]
});

db.users.find({
  $or: [
    { age: { $lt: 20 } },
    { age: { $gt: 60 } }
  ]
});

// === PROJEKCJA (wybór pól) ===
db.users.find(
  { age: { $gt: 25 } },
  { name: 1, email: 1, _id: 0 }  // Tylko name i email
);

// === SORTOWANIE I PAGINACJA ===
db.users.find()
  .sort({ age: -1 })    // Malejąco
  .skip(10)             // Pomiń 10
  .limit(5);            // Zwróć 5

Jak aktualizować i usuwać dokumenty?

Odpowiedź w 30 sekund: Update: updateOne(), updateMany() z operatorami $set, $unset, $inc, $push, $pull. Delete: deleteOne(), deleteMany(). Opcja upsert: true tworzy dokument jeśli nie istnieje.

Odpowiedź w 2 minuty:

Operacje aktualizacji i usuwania dokumentów z użyciem różnych operatorów:

// === UPDATE ===
// Aktualizuj jedno pole
db.users.updateOne(
  { email: "jan@example.com" },
  { $set: { age: 31 } }
);

// Wiele pól
db.users.updateOne(
  { _id: ObjectId("...") },
  {
    $set: { name: "Jan Nowak", status: "active" },
    $inc: { loginCount: 1 },
    $currentDate: { lastLogin: true }
  }
);

// Aktualizuj wiele dokumentów
db.users.updateMany(
  { status: "inactive" },
  { $set: { archived: true } }
);

// === OPERATORY TABLICOWE ===
// Dodaj element do tablicy
db.users.updateOne(
  { _id: ObjectId("...") },
  { $push: { tags: "premium" } }
);

// Dodaj wiele elementów
db.users.updateOne(
  { _id: ObjectId("...") },
  { $push: { tags: { $each: ["vip", "verified"] } } }
);

// Usuń element z tablicy
db.users.updateOne(
  { _id: ObjectId("...") },
  { $pull: { tags: "inactive" } }
);

// === UPSERT ===
db.users.updateOne(
  { email: "new@example.com" },
  { $set: { name: "New User", createdAt: new Date() } },
  { upsert: true }  // Utwórz jeśli nie istnieje
);

// === DELETE ===
db.users.deleteOne({ email: "jan@example.com" });

db.users.deleteMany({ status: "deleted" });

// Usuń wszystkie
db.users.deleteMany({});

Indeksy

Czym są indeksy w MongoDB i jak je tworzyć?

Odpowiedź w 30 sekund: Indeksy to struktury danych przyspieszające wyszukiwanie. Bez indeksu MongoDB skanuje całą kolekcję. Tworzy się je przez createIndex(). Typy: single field, compound, multikey (tablice), text, geospatial. Indeksy przyspieszają odczyt kosztem wolniejszego zapisu.

Odpowiedź w 2 minuty:

Przykłady tworzenia różnych typów indeksów oraz narzędzia do analizy wydajności zapytań:

// === TWORZENIE INDEKSÓW ===
// Single field index
db.users.createIndex({ email: 1 });  // 1 = ascending, -1 = descending

// Unique index
db.users.createIndex({ email: 1 }, { unique: true });

// Compound index (złożony)
db.users.createIndex({ lastName: 1, firstName: 1 });

// Text index (wyszukiwanie pełnotekstowe)
db.articles.createIndex({ title: "text", content: "text" });

// TTL index (auto-usuwanie)
db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 3600 }  // Usuń po 1h
);

// Partial index (tylko pasujące dokumenty)
db.users.createIndex(
  { email: 1 },
  { partialFilterExpression: { status: "active" } }
);

// === ANALIZA WYDAJNOŚCI ===
db.users.find({ email: "jan@example.com" }).explain("executionStats");

// Sprawdź czy używa indeksu
// "stage": "IXSCAN" = używa indeksu
// "stage": "COLLSCAN" = skan całej kolekcji (źle!)

// === ZARZĄDZANIE INDEKSAMI ===
db.users.getIndexes();           // Lista indeksów
db.users.dropIndex("email_1");   // Usuń indeks
db.users.dropIndexes();          // Usuń wszystkie (poza _id)

Kiedy tworzyć indeksy:

  • Pola często używane w zapytaniach (find, sort)
  • Pola w warunkach WHERE
  • Pola używane do JOIN ($lookup)

Kiedy unikać:

  • Kolekcje z częstymi zapisami
  • Pola o niskiej selektywności (np. boolean)
  • Małe kolekcje (< 1000 dokumentów)

Aggregation Pipeline

Czym jest Aggregation Pipeline i jak go używać?

Odpowiedź w 30 sekund: Aggregation Pipeline to framework do przetwarzania danych przez sekwencję etapów. Każdy etap ($match, $group, $project, $sort, $lookup) transformuje dokumenty i przekazuje wynik do następnego. Odpowiednik GROUP BY, JOIN i subqueries z SQL.

Odpowiedź w 2 minuty:

Agregacja danych przez sekwencję etapów - od filtrowania przez grupowanie po sortowanie i łączenie kolekcji:

// === PODSTAWOWA AGREGACJA ===
db.orders.aggregate([
  // 1. Filtruj (jak WHERE)
  { $match: { status: "completed" } },

  // 2. Grupuj (jak GROUP BY)
  {
    $group: {
      _id: "$customerId",
      totalOrders: { $sum: 1 },
      totalSpent: { $sum: "$amount" },
      avgOrder: { $avg: "$amount" }
    }
  },

  // 3. Filtruj grupy (jak HAVING)
  { $match: { totalSpent: { $gt: 1000 } } },

  // 4. Sortuj
  { $sort: { totalSpent: -1 } },

  // 5. Limit
  { $limit: 10 }
]);

// === $LOOKUP (JOIN) ===
db.orders.aggregate([
  {
    $lookup: {
      from: "customers",        // Kolekcja do połączenia
      localField: "customerId", // Pole w orders
      foreignField: "_id",      // Pole w customers
      as: "customer"            // Nazwa wyniku
    }
  },
  { $unwind: "$customer" },     // Rozpakuj tablicę
  {
    $project: {
      orderNumber: 1,
      amount: 1,
      customerName: "$customer.name"
    }
  }
]);

// === $UNWIND (rozwijanie tablic) ===
// Dokument: { name: "Jan", tags: ["js", "node", "mongo"] }
db.users.aggregate([
  { $unwind: "$tags" },
  { $group: { _id: "$tags", count: { $sum: 1 } } },
  { $sort: { count: -1 } }
]);
// Wynik: najpopularniejsze tagi

// === $PROJECT (transformacja) ===
db.users.aggregate([
  {
    $project: {
      fullName: { $concat: ["$firstName", " ", "$lastName"] },
      yearOfBirth: { $year: "$birthDate" },
      isAdult: { $gte: ["$age", 18] }
    }
  }
]);

Modelowanie danych

Kiedy używać embedding a kiedy referencing?

Odpowiedź w 30 sekund: Embedding (zagnieżdżanie): gdy dane są często odczytywane razem, relacja 1:few, dane rzadko się zmieniają. Referencing (referencje): gdy dokumenty są duże, relacja 1:many lub many:many, dane często aktualizowane niezależnie.

Odpowiedź w 2 minuty:

Porównanie dwóch podstawowych strategii modelowania relacji w MongoDB:

// === EMBEDDING (zagnieżdżanie) ===
// Dobre dla: 1:few, dane czytane razem
{
  _id: ObjectId("..."),
  name: "Jan Kowalski",
  addresses: [
    { type: "home", city: "Warszawa", street: "..." },
    { type: "work", city: "Kraków", street: "..." }
  ]
}
// ✅ Jeden odczyt = wszystkie dane
// ❌ Limit 16MB na dokument
// ❌ Duplikacja przy many-to-many

// === REFERENCING (referencje) ===
// Dobre dla: 1:many, many:many, duże dokumenty
// Kolekcja: users
{
  _id: ObjectId("user1"),
  name: "Jan Kowalski"
}

// Kolekcja: orders
{
  _id: ObjectId("order1"),
  userId: ObjectId("user1"),  // Referencja
  products: [
    { productId: ObjectId("prod1"), quantity: 2 }
  ],
  total: 150
}
// ✅ Brak limitu rozmiaru
// ✅ Dane aktualizowane niezależnie
// ❌ Wymaga $lookup (JOIN) lub wielu zapytań

Wzorce modelowania:

Relacja Strategia Przykład
1:1 Embedding User + Profile
1:few Embedding Post + Comments (kilka)
1:many Referencing User + Orders (setki)
many:many Referencing Users + Groups

Replikacja i Sharding

Czym jest Replica Set i jak działa?

Odpowiedź w 30 sekund: Replica Set to grupa serwerów MongoDB utrzymujących te same dane dla wysokiej dostępności. Składa się z Primary (obsługuje zapisy) i Secondary (repliki). Przy awarii Primary automatycznie wybierany jest nowy (election). Read preference pozwala czytać z Secondary.

Odpowiedź w 2 minuty:

Architektura Replica Set zapewnia wysoką dostępność przez replikację danych między wieloma serwerami:

┌─────────────────────────────────────────────┐
│              REPLICA SET                     │
│                                              │
│   ┌─────────┐    ┌─────────┐    ┌─────────┐ │
│   │ PRIMARY │───▶│SECONDARY│    │SECONDARY│ │
│   │ (write) │    │ (read)  │    │ (read)  │ │
│   └─────────┘    └─────────┘    └─────────┘ │
│        │              │              │       │
│        └──────────────┴──────────────┘       │
│                 Replikacja                   │
└─────────────────────────────────────────────┘

Read Preference:

// Czytaj z Primary (domyślne)
db.users.find().readPref("primary");

// Czytaj z Secondary (eventual consistency)
db.users.find().readPref("secondary");

// Preferuj Secondary, fallback do Primary
db.users.find().readPref("secondaryPreferred");

Write Concern:

// Potwierdzenie zapisu
db.users.insertOne(
  { name: "Jan" },
  { writeConcern: { w: "majority", j: true } }
);
// w: "majority" = większość nodów potwierdziła
// j: true = zapisano do journal (dysk)

MongoDB z Node.js

Jak używać Mongoose z Node.js?

Odpowiedź w 30 sekund: Mongoose to ODM (Object Document Mapper) dla MongoDB. Definiuje schematy, walidację, middleware (hooks), virtual fields i metody. Schema → Model → Document. Połączenie przez mongoose.connect(), operacje przez metody modelu.

Odpowiedź w 2 minuty:

Mongoose definiuje schematy z walidacją, middleware i metodami dla bezpiecznej pracy z MongoDB:

const mongoose = require('mongoose');

// === POŁĄCZENIE ===
mongoose.connect('mongodb://localhost:27017/myapp');

// === SCHEMA ===
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, 'Imię jest wymagane'],
    trim: true,
    minlength: 2
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    match: [/^\S+@\S+\.\S+$/, 'Nieprawidłowy email']
  },
  age: {
    type: Number,
    min: 0,
    max: 120
  },
  role: {
    type: String,
    enum: ['user', 'admin', 'moderator'],
    default: 'user'
  },
  createdAt: {
    type: Date,
    default: Date.now
  }
});

// === VIRTUAL FIELDS ===
userSchema.virtual('isAdult').get(function() {
  return this.age >= 18;
});

// === MIDDLEWARE (HOOKS) ===
userSchema.pre('save', async function(next) {
  if (this.isModified('password')) {
    this.password = await bcrypt.hash(this.password, 10);
  }
  next();
});

// === METODY ===
userSchema.methods.comparePassword = async function(candidate) {
  return bcrypt.compare(candidate, this.password);
};

// === MODEL ===
const User = mongoose.model('User', userSchema);

// === UŻYCIE ===
// Create
const user = await User.create({
  name: 'Jan',
  email: 'jan@example.com',
  age: 30
});

// Read
const users = await User.find({ age: { $gte: 18 } });
const user = await User.findById(id);
const user = await User.findOne({ email: 'jan@example.com' });

// Update
await User.findByIdAndUpdate(id, { age: 31 }, { new: true });

// Delete
await User.findByIdAndDelete(id);

Zobacz też


Ten artykuł jest częścią serii przygotowującej do rozmów rekrutacyjnych na stanowisko Backend Developer. Sprawdź nasze fiszki MongoDB z 44 pytaniami i odpowiedziami do nauki.

Chcesz więcej pytań rekrutacyjnych?

To tylko jeden temat z naszego kompletnego przewodnika po rozmowach rekrutacyjnych. Uzyskaj dostęp do 800+ pytań z 13 technologii.

Kup pełny dostęp Zobacz bezpłatny podgląd
Powrót do blogu

Zostaw komentarz

Pamiętaj, że komentarze muszą zostać zatwierdzone przed ich opublikowaniem.