2026'da NestJS ve MongoDB: Mongoose, Aggregation'lar ve Mülakat Soruları
NestJS ile MongoDB ve Mongoose 9 konusunda uzmanlaşın. Şema tasarım kalıplarını, aggregation pipeline'larını öğrenin ve pratik örneklerle teknik mülakatlarına hazırlanın.

NestJS 12, Mongoose 9 üzerinden MongoDB ile birleştirildiğinde, ölçeklenebilir Node.js backend'leri oluşturmak için üretime hazır bir stack sunmaktadır. Bu rehber, şema tasarım kalıplarını, aggregation pipeline'larını ve senior adayları junior'lardan ayıran mülakat sorularını kapsamaktadır.
Mongoose 9.9.4, Node.js 18+ gerektirmekte ve MongoDB 6.0'dan 8.0'a kadar desteklemektedir. NestJS 12, ESM'ye hazır paketler sunmakta, ancak CommonJS projeleriyle geriye dönük uyumluluğunu korumaktadır.
NestJS 12 Uygulamasında Mongoose Kurulumu
@nestjs/mongoose paketi, Mongoose'u NestJS bağımlılık enjeksiyonu ile entegre eder. Gerekli bağımlılıklar yüklenmektedir:
# Install Mongoose integration
npm install @nestjs/mongoose mongooseKök modülde bağlantı kaydedilir:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot(process.env.MONGODB_URI, {
// Connection pool size for production workloads
maxPoolSize: 10,
// Timeout after 10 seconds if connection fails
serverSelectionTimeoutMS: 10000,
}),
],
})
export class AppModule {}forRoot metodu tüm Mongoose bağlantı seçeneklerini kabul etmektedir. maxPoolSize ayarı, yük altında bağlantı tükenmesini önler; bu yaygın bir üretim sorunudur.
TypeScript Decorator'ları ile Şema Tasarımı
NestJS'te Mongoose şemaları, @nestjs/mongoose'dan decorator'ları kullanmaktadır. Her şema bir MongoDB koleksiyonuna eşlenmektedir.
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument, Types } from 'mongoose';
// Document type for TypeScript autocomplete
export type UserDocument = HydratedDocument<User>;
@Schema({
timestamps: true, // Adds createdAt and updatedAt
collection: 'users', // Explicit collection name
})
export class User {
// MongoDB ObjectId, auto-generated
_id: Types.ObjectId;
@Prop({ required: true, unique: true, index: true })
email: string;
@Prop({ required: true })
passwordHash: string;
@Prop({ type: String, enum: ['admin', 'user', 'guest'], default: 'user' })
role: string;
@Prop({ type: [String], default: [] })
permissions: string[];
}
export const UserSchema = SchemaFactory.createForClass(User);@Prop decorator'ı alan kısıtlamalarını tanımlar. Sık sorgulanan alanlarda index: true ayarı, yazma işlemlerini yavaşlatma pahasına okuma performansını artırır.
Mülakatçılar, gömülü belgeler ile referanslar arasındaki trade-off hakkında soru sormaktadır. Gömülü belgeler, birlikte erişilen veriler için uygundur (kullanıcı profili + tercihler). Referanslar, sınırsız büyüyen veya bağımsız sorgular gerektiren veriler için uygundur (kullanıcı + siparişler).
Enjekte Edilebilir Servisler ile Repository Kalıbı
NestJS, veritabanı mantığının servisler içinde ayrılmasını teşvik etmektedir. @InjectModel decorator'ı, Mongoose modeline erişim sağlar.
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import { User, UserDocument } from './user.schema';
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private userModel: Model<UserDocument>,
) {}
async findById(id: string): Promise<UserDocument> {
// Validate ObjectId format before querying
if (!Types.ObjectId.isValid(id)) {
throw new NotFoundException('Invalid user ID format');
}
const user = await this.userModel.findById(id).exec();
if (!user) {
throw new NotFoundException(`User ${id} not found`);
}
return user;
}
async findByEmail(email: string): Promise<UserDocument | null> {
// Case-insensitive email lookup
return this.userModel.findOne({
email: { $regex: new RegExp(`^${email}$`, 'i') }
}).exec();
}
async create(data: Partial<User>): Promise<UserDocument> {
const user = new this.userModel(data);
return user.save();
}
}.exec() çağrısı, Mongoose Query nesnesi yerine uygun bir Promise döndürmektedir. Bu, doğru async/await davranışı ve hata stack trace'leri için önemlidir.
Karmaşık Sorgular için Aggregation Pipeline'ları
MongoDB aggregation'ları, SQL veritabanlarının JOIN ve GROUP BY ile çözdüğü raporlama, analitik ve veri dönüşümlerini yönetmektedir.
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, PipelineStage } from 'mongoose';
import { Order, OrderDocument } from './order.schema';
@Injectable()
export class AnalyticsService {
constructor(
@InjectModel(Order.name) private orderModel: Model<OrderDocument>,
) {}
async getRevenueByMonth(year: number): Promise<MonthlyRevenue[]> {
const pipeline: PipelineStage[] = [
// Stage 1: Filter orders by year
{
$match: {
createdAt: {
$gte: new Date(`${year}-01-01`),
$lt: new Date(`${year + 1}-01-01`),
},
status: 'completed',
},
},
// Stage 2: Group by month, sum revenue
{
$group: {
_id: { $month: '$createdAt' },
totalRevenue: { $sum: '$amount' },
orderCount: { $sum: 1 },
avgOrderValue: { $avg: '$amount' },
},
},
// Stage 3: Sort by month ascending
{ $sort: { _id: 1 } },
// Stage 4: Reshape output
{
$project: {
_id: 0,
month: '$_id',
totalRevenue: { $round: ['$totalRevenue', 2] },
orderCount: 1,
avgOrderValue: { $round: ['$avgOrderValue', 2] },
},
},
];
return this.orderModel.aggregate(pipeline).exec();
}
}Aggregation pipeline'ları, belgeleri aşamalar boyunca sırayla işlemektedir. Her aşama, bir sonraki aşama için çıktıyı dönüştürür. $match aşaması erken filtreleme yaparak sonraki aşamalar tarafından işlenen belge sayısını azaltır.
Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Çoklu Belge İşlemleri için Transaction'lar
MongoDB 4.0+ çoklu belge ACID transaction'larını desteklemektedir. Birden fazla belgenin atomik olarak güncellenmesi gerektiğinde transaction'lar kullanılmalıdır.
import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
import { Connection, Model, ClientSession } from 'mongoose';
import { Account, AccountDocument } from './account.schema';
@Injectable()
export class TransferService {
constructor(
@InjectConnection() private connection: Connection,
@InjectModel(Account.name) private accountModel: Model<AccountDocument>,
) {}
async transfer(
fromId: string,
toId: string,
amount: number,
): Promise<void> {
// Start a session for the transaction
const session: ClientSession = await this.connection.startSession();
try {
await session.withTransaction(async () => {
// Debit source account
const source = await this.accountModel.findOneAndUpdate(
{ _id: fromId, balance: { $gte: amount } },
{ $inc: { balance: -amount } },
{ session, new: true },
);
if (!source) {
throw new BadRequestException('Insufficient balance or account not found');
}
// Credit destination account
const dest = await this.accountModel.findByIdAndUpdate(
toId,
{ $inc: { balance: amount } },
{ session, new: true },
);
if (!dest) {
throw new BadRequestException('Destination account not found');
}
});
} finally {
await session.endSession();
}
}
}session.withTransaction wrapper'ı, commit ve rollback işlemlerini otomatik olarak yönetir. Herhangi bir işlem hata fırlatırsa, tüm transaction iptal edilir.
Transaction'lar MongoDB replica set veya sharded cluster gerektirmektedir. Bağımsız MongoDB instance'ları transaction'ları desteklememektedir. Atlas M0/M2/M5 katmanları varsayılan olarak replica set'ler içermektedir.
Sorgu Performansı için İndeksleme Stratejileri
İndeksler sorgu performansını belirler. Uygun indeksler olmadan MongoDB tüm koleksiyonları tarar.
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
export type ProductDocument = HydratedDocument<Product>;
@Schema({ timestamps: true })
export class Product {
@Prop({ required: true, index: true })
sku: string;
@Prop({ required: true })
name: string;
@Prop({ required: true })
category: string;
@Prop({ required: true })
price: number;
@Prop({ default: true })
inStock: boolean;
}
export const ProductSchema = SchemaFactory.createForClass(Product);
// Compound index for common query pattern
ProductSchema.index({ category: 1, price: -1 });
// Text index for search functionality
ProductSchema.index({ name: 'text', sku: 'text' });Bileşik indeksler, birden fazla alana göre filtreleyen veya sıralayan sorguları destekler. { category: 1, price: -1 } indeksi, find({ category }).sort({ price: -1 }) gibi sorguları optimize eder.
NestJS ve MongoDB Hakkında Yaygın Mülakat Soruları
Teknik mülakatlar hem kavramsal anlayışı hem de pratik deneyimi test etmektedir. Bu sorular senior backend pozisyonlarında sıkça karşılaşılmaktadır.
S: Mongoose bağlantı pooling'ini nasıl yönetir?
Mongoose dahili olarak bir bağlantı havuzu sürdürmektedir. maxPoolSize seçeneği (varsayılan: 100) eşzamanlı bağlantıları sınırlar. Her işlem havuzdan bir bağlantı alır, çalıştırır ve geri döndürür. Bağlantı pooling, her sorgu için yeni TCP bağlantıları kurma yükünü ortadan kaldırır.
S: Referanslar yerine gömülü belgeler ne zaman kullanılmalıdır?
Birlikte ait olan ve sınırlı büyümesi olan verileri gömün. Kullanıcının teslimat adresleri (maksimum 5-10) iyi şekilde gömülür. Sipariş kalemleri sipariş belgesi içinde gömülür. Referanslar sınırsız ilişkiler için uygundur: kullanıcının yıllar içindeki siparişleri veya bir kategorideki ürünler. Kural: veriler zamanın %90'ında birlikte yükleniyorsa ve 16MB'ın altındaysa, gömün.
S: Aggregation pipeline'daki $lookup aşamasını açıklayın.
$lookup aşaması koleksiyonlar arasında left outer join gerçekleştirir. Alan eşitliğine veya özel bir pipeline'a dayalı olarak yabancı koleksiyondan belgeleri eşleştirir. SQL join'lerden farklı olarak, $lookup aggregation sırasında çalışır ve join içinde ek filtreleme ve projeksiyon içerebilir.
// Example: Orders with customer details
const pipeline: PipelineStage[] = [
{
$lookup: {
from: 'customers',
localField: 'customerId',
foreignField: '_id',
as: 'customer',
},
},
{ $unwind: '$customer' },
];S: MongoDB'de şema migrasyonlarını nasıl yönetirsiniz?
MongoDB şemaları SQL'den farklı şekilde evrilir. Yaygın stratejiler:
- Varsayılan değerlerle yeni alanlar ekleme (geriye dönük uyumlu)
- Mevcut belgeleri partiler halinde güncelleyen migrasyon scriptleri çalıştırma
schemaVersionalanı ile şema versiyonlama kullanma- Mongoose middleware'i (
pre('save')) yazma sırasında belgeleri dönüştürebilir
Senior adaylar trade-off'ları açıklar. Junior'lar özellikleri listeler. Gömülü vs referanslı belgeler sorulduğunda, sorgu kalıplarını, belge boyutu limitlerini (16MB) ve güncelleme sıklığını tartışın, sadece "duruma bağlı" demeyin.
Hata Yönetimi ve Validasyon Kalıpları
Mongoose validasyonu kaydetme işlemlerinden önce çalışır. Özel validator'lar iş mantığını yönetir.
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
export type OrderDocument = HydratedDocument<Order>;
@Schema({ timestamps: true })
export class Order {
@Prop({
required: true,
validate: {
validator: (v: number) => v > 0,
message: 'Amount must be positive',
},
})
amount: number;
@Prop({
type: String,
enum: ['pending', 'processing', 'completed', 'cancelled'],
default: 'pending',
})
status: string;
@Prop({ required: true })
items: OrderItem[];
}
export const OrderSchema = SchemaFactory.createForClass(Order);
// Pre-save hook for computed fields
OrderSchema.pre('save', function (next) {
// Recalculate total from items
if (this.isModified('items')) {
this.amount = this.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0,
);
}
next();
});pre('save') middleware'i her kaydetme işleminden önce çalışır. Hesaplanan alanlar, denetim günlüğü veya kademeli güncellemeler için kullanılır.
explain() ile Performans İzleme
explain() metodu sorgu yürütme planlarını ortaya koyar. Eksik indeksleri ve yavaş sorguları tespit etmek için kullanılır.
// Debug query performance
async analyzeQuery(category: string): Promise<void> {
const explanation = await this.productModel
.find({ category, inStock: true })
.sort({ price: -1 })
.explain('executionStats');
console.log('Documents examined:', explanation.executionStats.totalDocsExamined);
console.log('Documents returned:', explanation.executionStats.nReturned);
console.log('Execution time (ms):', explanation.executionStats.executionTimeMillis);
// If totalDocsExamined >> nReturned, add an index
}totalDocsExamined ile nReturned oranının 1'e yakın olması verimli indeks kullanımını gösterir. Yüksek oranlar eksik indeksleri veya seçici olmayan sorguları işaret eder.
NestJS MongoDB Geliştirme için Önemli Çıkarımlar
maxPoolSize'ı beklenen eşzamanlılığa göre yapılandırın, varsayılan 100 çoğu iş yükü için uygundur- Mongoose belgelerinin düzgün TypeScript tiplemesi için
HydratedDocument<T>kullanın - Doğru stack trace'ler ile native Promise'lar almak için sorgularda
.exec()çağırın - İşlenen belgeleri azaltmak için aggregation pipeline'larında
$matchaşamalarını erken yerleştirin - Transaction'lar replica set'ler gerektirir, güvenmeden önce dağıtım topolojisini doğrulayın
- Sorgu kalıplarıyla eşleşen bileşik indeksler oluşturun: önce filtre alanları, sonra sıralama alanları
- Sınırlı büyümesi olan belgeleri gömün, sınırsız büyüyen belgeleri referanslayın
- Geliştirme sırasında
explain('executionStats')ile sorgu performansını izleyin
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Node.js / NestJS kodundaki hatayı bulabilir misin?
Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Yazan:
Anthony Fillion-MailletSharpSkill kurucusu
10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.
28 Ağustos 2026 tarihinde güncellendi
Etiketler
Paylaş
İlgili makaleler

NestJS + Prisma: Node.js için modern backend yığını
NestJS ve Prisma ile modern bir backend API'si oluşturmak için kapsamlı rehber. Kurulum, modeller, servisler, transaction'lar ve en iyi uygulamalar.

Node.js Backend Mülakat Soruları: Kapsamlı Rehber 2026
Node.js backend mülakatlarında en sık sorulan 25 soru. Event loop, async/await, stream, kümeleme ve performans konuları detaylı cevaplarla açıklanmaktadır.

NestJS: Eksiksiz bir REST API Oluşturma
NestJS ile profesyonel bir REST API oluşturmak için kapsamlı rehber. Controller, Service, Module yapıları, class-validator ile doğrulama ve hata yönetimi pratik örneklerle açıklanmaktadır.