1. Prisma ORM
- Prisma ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ๋จ์ํํ๋ ์คํ์์ค ORM์ด๋ค.
- ํ์ ์์ ์ฑ (type safe)์ ๊ฐ์ถ ์ฟผ๋ฆฌ ์์ฑ ๋ฐ ์คํค๋ง ๋ง์ด๊ทธ๋ ์ด์ ์ ์ง์ํ๋ค.
- PostgreSQL, MySQL, SQLite๋ฑ ์ธ๊ธฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ง์ํ๋ค.
- Prisma Schema Langauge๋ผ๋ ํ์คํ๋ ์ธ์ด๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ์๋ฅผ ๋งคํ ํ ์ ์๋ค.
Data Source: ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฐ๊ฒฐ์ ์ ์ํ๋ค.Generator: ์ด๋ค ํด์ด ์์ฑ๋ ์ง ์ ์ํ๋ค. (Prisma Client ๋ฑ)Models: ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์นผ๋ผ๋ค์ ์ ์ํ๋ค. TypeORM์ Entity๊ฐ์ ์ ์๋ผ๊ณ ๋ณผ ์ ์๋ค.Enums: ํน์ ํ๋์ ํ๊ฐ๋๋ ๊ฐ๋ค์ ์ ์ํ๋ค.Relations: ๋ชจ๋ธ๊ฐ ๊ด๊ณ๋ฅผ ์ค์ ํ ์ ์๋ค. (One to One, Many to Many๋ฑ)
1.1 Prisma Schema Langauge
1.1.1 DataSource
1datasource db {2provider = "postgresql"3url = "postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public"4}
- provider๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ ์ ์ ์ํ๋ค. postgresql, mysql, sqlite๋ฑ
- url์ ์ฐ๊ฒฐ URL์ ์ ์ํ๋ค.
{db_type}://{username}:{password}@{host}:{port}/{db_name}?schema={schema}
1.1.2 Generator
1generator client {2provider = 'prisma-client-js'3output = './generated/prisma-client-js'4}
- provider๋ ์ ๋๋ ์ดํฐ ํด์ ์ ์ํ๋ค.
- output์ API ํ์ผ์ ์์ฑํ ์์น๋ฅผ ์ ์ํ๋ค
1.1.3 Model
1model Comment {2id Int @id @default(autoincrement())3title String4content String5}67model Tag {8name String @id9}
- Model์ ํ ์ด๋ธ ์ ๋ณด๋ฅผ ์ ์ํ๋ค.
- Scalar, Relation, Type Modifier ๋ฑ์ ์ฌ์ฉํด์ ํ ์ด๋ธ์ ์ ์ํ ์ ์๋ค
1.1.4 Enum
1model User {2id Int @id @default(autoincrement())3email String @unique4name String?5role Role @default(USER)6}78enum Role {9USER10ADMIN11}
- TypeORM์์ ๋ค๋ค๋ enum ๊ฐ๋ ๊ณผ ๊ฐ๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
- ํน์ ๊ฐ๋ง ์ ๋ ฅ๋๋๋ก ์ ๋ ํ ์ ์๋ค
1.1.5 Relations
1model User {2id Int @id @default(autoincrement())3name String4posts Post[]5}67model Post {8id Int @id @default(autoincrement())9title String10userId Int11user User @relation(fields: [userId], references: [id], onDelete: Cascade)12}
- Relation์ One to One, One to Many, Many to Many Relationship์ ํ์ฑํ ๋ ์ฌ์ฉ๋๋ค.
- fields์ ๋ ํผ๋ฐ์ค๋ก ์ฌ์ฉํ ์์ ์ ์นผ๋ผ์ ์ ๋ ฅํ๊ณ references์ ์๋ ์นผ๋ผ์ ์ ๋ ฅํ๋ค.
- onDelete, onUpdate๋ฑ attribute ์ ์๋ ๊ฐ๋ฅํ๋ค
1.2 Scalar Types
| ํ์ | Scalar ํ์ |
|---|---|
| String | Text |
| Boolean | Boolean |
| Int | Integer |
| BigInt | BigInt |
| Float | Real/Double Precision |
| Decimal | Numeric |
| DateTime | Timestamp/ Timestamptz |
| Json | JSON/JSONB |
| Bytes | BYTEA |
1.3 Attributes
| ์์ฑ | ์ค๋ช |
|---|---|
| @id | Primary Key |
| @default | ๊ธฐ๋ณธ๊ฐ |
| @unique | ์ ๋ํฌ/์ ์ผ๋ฌด์ด ๊ฐ |
| @relation | ๋ชจ๋ธ ๊ฐ ๊ด๊ณ |
| @map | ํ ์ด๋ธ์ ๋ค๋ฅธ ์นผ๋ผ์ผ๋ก ๋งคํ |
| @updatedAt | ์ ๋ฐ์ดํธ ์๊ฐ DateTime ๊ธฐ๋ก |
| @@id | Composite Primary Key |
| @@unique | Composite Unique Key |
| @@index | Index Keys |
1.4 Prisma Client
1genreator client {2provider = 'prisma-client-js'3}
1$ npm install @prisma/client2$ prisma generate
- generator์ prisma client ์ ์
- @prisma/client ์ค์น
- prisma generate ์คํ (@prisma/client ์ค์น์ ์๋ ์คํ)
1.4.1 Prisma Client ์์ ํ๋ก์ฐ

1.4.2 Prisma Client ์๋ ๋ฐฉ์

1.4.3 Prisma Create
1const user = await prisma.user.create({2data: {3email: 'admin@codefactory.ai',4name: 'Code Factory',5},6})
1const createMany = await prisma.user.createMany({2data: [3{ email: '๋ฏผ์ง', email: 'minji@codefactory.ai' },4{ email: '์ฌ๊ธฐ', email: 'seulgi@codefactory.ai' },5{ email: '์์', email: 'minji@codefactory.ai' }, // ์ค๋ณต ํค6{ email: '๋ค๋ฏธ', email: 'dami@codefactory.ai' },7],8skipDuplicates: true, // ์์ ์คํต๋จ9})
1.4.4 Prisma Read (1)
1const user = await prisma.user.findUniquye({2where: { email: 'minji@codefactory.ai' },3})
1const result = await prisma.user.findFirst({2where: {3email: { endsWith: 'codefactory.ai' },4},5})
1.4.5 Prisma Read (2)
1const user = await prisma.user.findMany({2where: {3email: { endsWith: 'codefactory.ai' },4},5})
1const users = await prisma.user.findMany({2where: {3OR: [4{ name: { startsWith: 'E' } },5{6AND: {7profileViews: { gt: 0 },8role: { equals: 'ADMIN' },9},10},11],12},13})
1.5 Prisma Operators
| ์์ฑ | ์ค๋ช |
|---|---|
| equals | ๊ฐ์ ๊ฐ |
| not | ์๋ ๊ฐ |
| in | ํฌํจํ๋ ๊ฐ |
| notin | ํฌํจํ์ง ์๋ ๊ฐ |
| lt | ์ ์ ๊ฐ |
| lte | ์ ๊ฑฐ๋ ๊ฐ์ ๊ฐ |
| gt | ํฐ ๊ฐ |
| gte | ํฌ๊ฑฐ๋ ๊ฐ์ ๊ฐ |
| contains | ํฌํจํ๋ ๊ฐ |
| search | ๊ฒ์ (Full Text Search) |
| startWith | ์์ํ๋ ๊ฐ |
| endsWith | ๋๋๋ ๊ฐ |
| AND | && |
| OR | || |
| NOT | ์๋ ๊ฐ |
1.5.1 Prisma Read ํ๋ ์ ํํ๊ธฐ
1const getUser = await prisma.user.findUnique({2where: { id: 22 },3select: {4email: true,5name: true,6},7})
email๊ณผ name ์นผ๋ผ๋ง ์ ํ
1.5.2 Prisma Read Relation ํฌํจํ๊ธฐ
1const users = await prisma.user.findMany({2include: {3posts: {4select: { title: true },5},6},7})
user ๊ฐ์ post ๊ด๊ณ ํฌํจํด์ ๋ฐํ
1.5.3 Relation Filtering Some
1const result = await prisma.user.findMany({2where: {3post: {4some: {5content: { contains: 'Code Factory' },6},7},8},9})
Code Factory๋ฅผ content์ ํฌํจํ๊ณ ์๋ post๊ฐ ์กด์ฌํ๋ user๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ด
1.5.4 Relation Filtering Every
1const result = await prisma.user.findMany({2where: {3post: {4every: { published: true },5},6},7})
๊ด๋ จ๋ post์ published๊ฐ ๋ชจ๋ true์ธ user๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ด
1.5.5 Relation Filtering None
1const result = await prisma.user.findMany({2where: {3post: {4none: { published: true },5},6},7})
๊ด๋ จ๋ post์ published๊ฐ ๋ชจ๋ true๊ฐ ์๋ User๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ด
1.5.6 Relation Filtering Is
1const result = await prisma.user.findMany({2where: {3user: {4is: { name: 'Code Factory' },5},6},7})
name ํ๋๊ฐ Code Factory์ธ post๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ด
1.5.7 Relation Filtering IsNot
1const result = await prisma.user.findMany({2where: {3user: {4isNot: { name: 'Code Factory' },5},6},7})
name ํ๋๊ฐ Code Factory๊ฐ ์๋ User๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ด
1.5.8 Update
1const updateUser = await prisma.user.update({2where: { email: 'test@codefactory.ai' },3data: { name: '๋ฏผ์ง' },4})
์ฌ์ฉ์์ name ํ๋๋ฅผ โ๋ฏผ์งโ๋ก ๋ณ๊ฒฝ
1.5.9 Delete
1const deleteUser = await prisma.user.delete({2where: { email: 'test@codefactory.ai' },3})
email์ด test@codefactory.ai์ธ ์ฌ์ฉ์๋ฅผ ์ญ์
1.5.10 Relationship One to One
1model User {2id Int @id @default(autoincrement())3profile Profile @relation(fields: [profileId], references: [id])4profileId Int @unique // ํ์ (1:1์ด๋๊นใ ฃ ๋น์ฐํ)5}67model Profile {8id Int @id @default(autoincrement())9user User? // nullable๋ง ๊ฐ๋ฅ10}
1model User {2id Int @id @default(autoincrement())3profile Profile? @relation(fields: [profileId], references: [id])4profileId Int? @unique // Optional ์์ฑ ๊ฐ๋ฅ5}67model Profile {8id Int @id @default(autoincrement())9user User?10}
1.5.11 Relationship One to Many
1model User {2id Int @id @default(autoincrement())3posts Post[]4}56model Post {7id Int @id @default(autoincrement())8author User @relation(fields: [authorId], references: [id])9authorId Int10}
1.5.12 Relationship Many to Many
1model Post {2id Int @id @default(autoincrement())3title String4categories CategoriesOnPosts[]5}67model Category {8id Int @id @default(autoincrement())9name String10posts CategoriesOnPosts[]11}1213model CategoriesOnPosts {14post Post @relation(fields: [postId], references: [id])15postId Int16category Category @relation(fields: [categoryId], references: [id])17categoryId Int18assignedAt DateTime @default(now())19assignedBy String20@@id([postId, categoryId])21}
1model Post {2id Int @id @default(autoincrement())3title String4categories Category[]5}67model Category {8id Int @id @default(autoincrement())9name String10posts Post[]11}
1.6 Aggregate Function
| ํจ์ | ์ค๋ช |
|---|---|
_avg | ํ๊ท |
_count | ๊ฐฏ์ |
_sum | ํฉ๊ณ |
_min | ์ต์ ๊ฐ |
_max | ์ต๋ ๊ฐ |
1.6.1 Aggregate
1const aggregations = await prisma.user.aggregate({2_avg: { age: true },3})
1.6.2 Raw Query
1const result = await prisma.$queryRaw('SELECT * FROM User')
1.6.3 Migration
1# prisma migrate dev > ๋ง์ด๊ทธ๋ ์ด์ ํ์ผ ์์ฑ (์๋)2prisma migrate dev --name "add-new-field"
1# prisma migrate deploy > ๋ง์ด๊ทธ๋ ์ด์ ์งํ2prisma migrate deploy
2. Mongodb
2.1 NoSQL vs SQL
- SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๋ฏธ๋ฆฌ ์ ์๋ ๊ตฌ์กฐํ๋ Table๊ณผ Column, Row๋ฅผ ์ฌ์ฉํ๋ค.
- NoSQL์ ๊ตฌ์กฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ํ ํ์๊ฐ ์๋ค.
- Document, Key-Value Pair ๋๋ Graph ํํ๋ก ๋ชจ๋ ๊ฐ์ ์ํ๋ ํํ๋ก ์ ์ฅ ํ ์ ์๋ค.
- NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ข
๋ฅ
- Document โ Mongodb
- Key Value โ Redis
- Column โ Cassandra
- Graph โ Neo4J
- NoSQL์ ์ฌ์ฉํด์ผํ๋ ์ด์ ?
- NoSQL์ SQL์ ๋นํด ๋งค์ฐ ์ ์ฐํ๊ณ ์ํ์ ์ค์ผ์ผ๋ง (Horizontal Scaling)์ ๋งค์ฐ ์ ๋ฆฌํ๋ค.
- ๋๋์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ์ํด ์ค๊ณ๋๋ค.
- ์ง์์ ์ผ๋ก ๊ตฌ์กฐ๊ฐ ๋ณํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ๋ ๋งค์ฐ ์ ๋ฆฌํ๋ค
2.2 MongoDB
- MongoDB๋?
- MongoDB๋ Document ๊ธฐ๋ฐ์ NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ค.
- JSON๊ณผ ์ ์ฌํ ๊ตฌ์กฐ (BSON) ๊ตฌ์กฐ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค.
- ์ค์ผ์ผ๋ง์ด ์ฝ๊ณ ์ ์ฐํ๊ณ ์ฌ์ฉ์ฑ์ด ํธ๋ฆฌํ๋ค.
- MongoDB์ ๋ฐ์ดํฐ ๊ตฌ์กฐ
- Document ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค. SQL์์์ Row์ ๊ฐ์ ๋จ์๋ค.
- Collection์ ๋น์ทํ Document๋ค์ ๋ณด๊ดํ๋ค. SQL์์์ Table๊ณผ ๊ฐ์ ๋จ์๋ค
1{2"name": "John Doe",3"age": 30,4"email": "john@example.com",5"interests": ["hiking", "coding"]6}
2.3 ๊ธฐ๋ณธ MongoDB CRUD ์์
๋ฐ์ดํฐ ์์ฑ (Create)insertOne(): ํ๊ฐ์ Document๋ฅผ ์์ฑinsertMany(): ์ฌ๋ฌ๊ฐ์ Document๋ฅผ ์์ฑ
๋ฐ์ดํฐ ์กฐํ (Read)find(): ์ฌ๋ฌ๊ฐ์ Document ์กฐํfindOne(): ํ๊ฐ์ Document ์กฐํ
๋ฐ์ดํฐ ์ ๋ฐ์ดํธ (Update)updateOne(): ํ๊ฐ์ Document ์ ๋ฐ์ดํธupdateMany(): ์ฌ๋ฌ๊ฐ์ Document ์ ๋ฐ์ดํธ
๋ฐ์ดํฐ ์ญ์ (Delete)deleteOne(): ํ๊ฐ์ Document ์ญ์ deleteMany(): ์ฌ๋ฌ๊ฐ์ Document ์ญ์
2.4 Mongoose (ODM)
Prisma, TypeORM๊ฐ์ Javascript SQL ORM์ด ์กด์ฌํ๋ ๊ฒ์ฒ๋ผ MongoDB๋ Mongoose๋ผ๋ ODM์ด ์กด์ฌํ๋ค.
๊ธฐ๋ณธ๊ธฐ: ์ฐ๊ฒฐํ๊ธฐ, CRUD, Populate๊ณ ๊ธ๊ธฐ๋ฅ: Middleware (Hook), VirtualPropertyRelationship: One to Many, Many to ManyTransaction
2.4.1 Mongoose (์ฐ๊ฒฐํ๊ธฐ)
1const mongoose = require('mongoose')23async function connectDB() {4try {5await mongoose.connect('mongodb://localhost:27017/mydb')6console.log('MongoDB Connected')7} catch (err) {8console.error('Connection Error:', err)9}10}1112connectDB()
2.4.2 Mongoose (Schema ์ ์ํ๊ธฐ)
1const userSchema = new mongoose.Schema({2name: String,3age: Number,4email: String,5interests: [String],6})78const User = mongoose.model('User', userSchema)910const newUser = new User({11name: 'Code Factory',12age: 25,13email: 'admin@codefactory.ai',14interests: ['reading', 'music'],15})
2.4.3 Mongoose (Create ์์ ํ๊ธฐ)
1async function createUser() {2try {3const user = await User.create({4name: '๋ฏผ์ง',5age: 21,6email: 'minji@codefactory.ai',7interests: ['dancing', 'singing'],8})9console.log('User created:', user)10} catch (err) {11console.error('Error creating user:', err)12}13}
2.4.4 Mongoose (Read ์์ ํ๊ธฐ)
1async function findAllUsers() {2try {3const users = await User.find({})4console.log('User found:', users)5} catch (err) {6console.error('Error finding users:', err)7}8}
2.4.5 Mongoose (Update ์์ ํ๊ธฐ)
1async function updateUser() {2try {3const updateUser = await User.updateOne(4{ email: '๋ฏผ์ง' }, //5{ $set: { age: 22 } },6)7console.log('User updated:', updateUser)8} catch (err) {9console.error('Error updating user:', err)10}11}
2.4.6 Mongoose (Delete ์์ ํ๊ธฐ)
1async function deleteUser() {2try {3const deleteUser = await User.deleteOne({ name: '๋ฏผ์ง' })4console.log('User deleted:', deleteUser)5} catch (err) {6console.error('Error deleting user:', err)7}8}
2.4.7 Mongoose (Populate ์ ์ฌ Join)
1const userSchema = new mongoose.Schema({2name: String,3age: Number,4email: String,5interests: [String],6})78const postSchema = new mongoose.Schema({9title: String,10author: {11type: mongoose.Schema.Types.ObjectId,12ref: 'User',13},14})1516async function findPostsWithAuthors() {17try {18const posts = await Post.find().populate('author').exec()19console.log('Posts & authors:', posts)20} catch (err) {21console.error('Error : ', err)22}23}
2.4.8 Mongoose (Middleware Hook)
1userSchema.pre('save', function (next) {2console.log('Saving user:', this.name)3next()4})56const User = mongoose.model('User', userSchema)
- pre โ ์ด๋ฒคํธ ์คํ ์ / pos โ ์ด๋ฒคํธ ์คํ ํ
Document Middleware: save, validate, remove๋ฑ ์ด๋ฒคํธ ์คํ์ ์คํQuery Middleware:- updateOne, deleteOne, findOneAndUpdate๋ฑ ํน์ ํจ์ ์คํ์ ์คํ (Query Middleware)
2.5 Mongoose Relationships
2.5.1 One to One
1const mongoose = require('mongoose')23const profileSchema = new mongoose.Schema({4bio: String,5website: String,6location: String,7})89const userSchema = new mongoose.Schema({10name: String,11email: String,12profile: {13type: mongoose.Schema.Types.ObjectId,14ref: 'Profile',15},16})
1const userSchema = new mongoose.Schema({2name: String,3email: String,4profile: {5bio: String,6website: String,7location: String,8},9})
2.5.2 One to Many
1const commentSchema = new mongoose.Schema({2body: String,3date: Date,4postId: {5type: mongoose.Schema.Types.ObjectId,6ref: 'Post',7},8})910const postSchema = new mongoose.Schema({11title: String,12content: String,13comments: [14{15type: mongoose.Schema.Types.ObjectId,16ref: 'Comment',17},18],19})
2.5.3 Many to Many
1const roleSchema = new mongoose.Schema({2name: String,3users: [4{5type: mongoose.Schema.Types.ObjectId,6ref: 'User',7},8],9})1011const userSchema = new mongoose.Schema({12name: String,13roles: [14{15type: mongoose.Schema.Types.ObjectId,16ref: 'Role',17},18],19})
2.5.4 Mongoose (Transaction)
1const session = await mongoose.startSession()2session.startTransaction()34try {5const user = new User({ name: '๋ฏผ์ง', email: 'minji@codefactory.ai' })6await user.save({ session })78const post = new Post({ title: "Minji's Post", author: user._id })9await post.save({ session })1011await session.commitTransaction() // ์ปค๋ฐ12session.endSession() // ์ธ์ ์ข ๋ฃ13} catch (error) {14await session.abortTransaction() // ๋กค๋ฐฑ15session.endSession()16throw error17}