371 lines
9.1 KiB
TeX
371 lines
9.1 KiB
TeX
\section{Aggregációk}
|
|
|
|
\begin{frame}{Mi az aggregáció?}
|
|
\begin{block}{Aggregált lekérdezések}
|
|
Adatok összesítése és elemzése számítások segítségével
|
|
\end{block}
|
|
|
|
\begin{block}{Prisma aggregáció műveletek}
|
|
\begin{itemize}
|
|
\item \texttt{count} - Rekordok számlálása
|
|
\item \texttt{avg} - Átlag számítás
|
|
\item \texttt{sum} - Összegzés
|
|
\item \texttt{min} - Minimum érték
|
|
\item \texttt{max} - Maximum érték
|
|
\item \texttt{groupBy} - Csoportosítás
|
|
\end{itemize}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Példa séma}
|
|
\begin{block}{schema.prisma - Product}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
model Product {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
price Float
|
|
stock Int
|
|
categoryId Int
|
|
category Category @relation(fields: [categoryId],
|
|
references: [id])
|
|
createdAt DateTime @default(now())
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Példa séma (folyt.)}
|
|
\begin{block}{schema.prisma - Category}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
model Category {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
products Product[]
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Count - Számlálás}
|
|
\begin{block}{Összes rekord számolása}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
const prisma = require('./prisma');
|
|
async function countProducts() {
|
|
const count = await prisma.product.count();
|
|
console.log(`Összes termék: ${count}`);
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Count - Számlálás (szűréssel)}
|
|
\begin{block}{Szűrt számlálás}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function countExpensiveProducts() {
|
|
const count = await prisma.product.count({
|
|
where: {
|
|
price: {
|
|
gt: 1000
|
|
}
|
|
}
|
|
});
|
|
console.log(`Drága termékek: ${count}`);
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Aggregate - Alapok}
|
|
\begin{block}{Egyszerű aggregáció}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function getProductStats() {
|
|
const stats = await prisma.product.aggregate({
|
|
_count: true,
|
|
_avg: {price: true},
|
|
_sum: {stock: true},
|
|
_min: {price: true},
|
|
_max: {price: true}
|
|
});
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Aggregate - Alapok (folyt.)}
|
|
\begin{block}{Egyszerű aggregáció}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
console.log(stats);
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Aggregate - Eredmény}
|
|
\begin{block}{Visszatérési érték példa}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
{
|
|
_count: 150,
|
|
_avg: {
|
|
price: 1250.50
|
|
},
|
|
_sum: {
|
|
stock: 5420
|
|
},
|
|
_min: {
|
|
price: 99.99
|
|
},
|
|
_max: {
|
|
price: 9999.99
|
|
}}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Aggregate - Szűréssel}
|
|
\begin{block}{Where feltétellel}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function getCategoryStats(categoryId) {
|
|
const stats = await prisma.product.aggregate({
|
|
where: {
|
|
categoryId: categoryId
|
|
},
|
|
_count: true,
|
|
_avg: {
|
|
price: true
|
|
},
|
|
_sum: {
|
|
stock: true
|
|
}
|
|
});
|
|
return stats;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{GroupBy - Csoportosítás}
|
|
\begin{block}{Kategóriánkénti csoportosítás}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function groupByCategory() {
|
|
const result = await prisma.product.groupBy({
|
|
by: ['categoryId'],
|
|
_count: true,
|
|
_avg: {
|
|
price: true
|
|
},
|
|
_sum: {
|
|
stock: true
|
|
}
|
|
});
|
|
|
|
return result;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{GroupBy - Eredmény}
|
|
\begin{block}{Csoportosított adatok}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
[
|
|
{
|
|
categoryId: 1,
|
|
_count: 45,
|
|
_avg: { price: 599.99 },
|
|
_sum: { stock: 1200 }
|
|
},
|
|
{
|
|
categoryId: 2,
|
|
_count: 67,
|
|
_avg: { price: 1299.50 },
|
|
_sum: { stock: 890 }
|
|
}
|
|
]
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{GroupBy - Having feltétel}
|
|
\begin{block}{Szűrés az aggregált eredményen}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function getCategoriesWithHighAvgPrice() {
|
|
const result = await prisma.product.groupBy({
|
|
by: ['categoryId'],
|
|
_avg: {price: true},
|
|
_count: true,
|
|
having: {
|
|
price: {
|
|
_avg: {gt: 1000}
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{GroupBy - Rendezés}
|
|
\begin{block}{OrderBy aggregált mezőn}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function getCategoriesOrderedByAvgPrice() {
|
|
const result = await prisma.product.groupBy({
|
|
by: ['categoryId'],
|
|
_avg: {price: true},
|
|
_count: true,
|
|
orderBy: {
|
|
_avg: {price: 'desc'}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Több mező szerinti csoportosítás}
|
|
\begin{block}{Összetett GroupBy}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
// Bővített séma szükséges: inStock boolean mező
|
|
async function groupByCategoryAndStock() {
|
|
const result = await prisma.product.groupBy({
|
|
by: ['categoryId', 'inStock'],
|
|
_count: true,
|
|
_avg: {price: true},
|
|
orderBy: {categoryId: 'asc'}
|
|
});
|
|
return result;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Relációk és aggregáció}
|
|
\begin{block}{Kapcsolt táblák aggregálása}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function getCategoriesWithProductCount() {
|
|
const categories = await prisma.category.findMany({
|
|
include: {
|
|
_count: {
|
|
select: {
|
|
products: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
// Eredmény: [{ id: 1, name: 'Electronics',
|
|
// _count: { products: 45 } }, ...]
|
|
return categories;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Relációs szűrés aggregációval}
|
|
\begin{block}{Több mint N termékkel rendelkező kategóriák}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function getCategoriesWithManyProducts() {
|
|
const categories = await prisma.category.findMany({
|
|
where: {
|
|
products: {some: {}}
|
|
},
|
|
include: {
|
|
_count: {
|
|
select: {products: true}
|
|
}
|
|
}});
|
|
// Csak azok a kategóriák, amikhez van termék
|
|
return categories.filter(c => c._count.products > 10);
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Express API - Statisztika endpoint}
|
|
\begin{block}{Aggregált adatok REST API-n keresztül}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
const express = require('express');
|
|
const prisma = require('./prisma');
|
|
const app = express();
|
|
|
|
app.get('/api/stats/products', async (req, res) => {
|
|
const stats = await prisma.product.aggregate({
|
|
_count: true,
|
|
_avg: { price: true },
|
|
_sum: { stock: true },
|
|
_min: { price: true },
|
|
_max: { price: true }
|
|
});
|
|
res.json(stats);
|
|
});
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Express API - Csoportosított adatok}
|
|
\begin{block}{GroupBy endpoint}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
app.get('/api/stats/by-category', async (req, res) => {
|
|
const stats = await prisma.product.groupBy({
|
|
by: ['categoryId'],
|
|
_count: true,
|
|
_avg: { price: true },
|
|
_sum: { stock: true },
|
|
orderBy: {
|
|
_avg: {
|
|
price: 'desc'
|
|
}
|
|
}
|
|
});
|
|
res.json(stats);
|
|
});
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Egyedi aggregáció - Raw Query}
|
|
\begin{block}{SQL használata komplex esetekben}
|
|
\begin{lstlisting}[language=JavaScript]
|
|
async function customAggregation() {
|
|
const result = await prisma.$queryRaw`
|
|
SELECT "categoryId",
|
|
COUNT(*) as count,
|
|
AVG(price) as avgPrice,
|
|
SUM(stock) as totalStock
|
|
FROM "Product"
|
|
WHERE price > 100
|
|
GROUP BY "categoryId"
|
|
HAVING AVG(price) > 500
|
|
ORDER BY avgPrice DESC
|
|
`;
|
|
return result;
|
|
}
|
|
\end{lstlisting}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Aggregáció - Best Practices}
|
|
\begin{block}{Ajánlások}
|
|
\begin{itemize}
|
|
\item Használj \texttt{select} és \texttt{where} feltételeket a teljesítmény növelésére
|
|
\item GroupBy esetén mindig gondold át az indexelést
|
|
\item Nagy adathalmazoknál fontold meg a lapozást
|
|
\item Komplex esetekben raw SQL lehet hatékonyabb
|
|
\item Cacheld az aggregált eredményeket, ha ritkán változnak
|
|
\item Használj \texttt{having} feltételt az aggregált adatok szűrésére
|
|
\end{itemize}
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Összefoglalás}
|
|
\begin{block}{Prisma aggregációk}
|
|
\begin{itemize}
|
|
\item \textbf{count} - Egyszerű és szűrt számlálás
|
|
\item \textbf{aggregate} - Átlag, összeg, min, max számítások
|
|
\item \textbf{groupBy} - Csoportosítás és aggregálás
|
|
\item \textbf{having} - Szűrés aggregált eredményen
|
|
\item \textbf{orderBy} - Rendezés aggregált mezők szerint
|
|
\item \textbf{\_count} - Kapcsolt rekordok számlálása
|
|
\end{itemize}
|
|
\end{block}
|
|
\end{frame}
|