๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Back
NestJs
46-Prisma Mongodb

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

1
datasource db {
2
provider = "postgresql"
3
url = "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

1
generator client {
2
provider = 'prisma-client-js'
3
output = './generated/prisma-client-js'
4
}
  • provider๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํˆด์„ ์ •์˜ํ•œ๋‹ค.
  • output์€ API ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์œ„์น˜๋ฅผ ์ •์˜ํ•œ๋‹ค

1.1.3 Model

1
model Comment {
2
id Int @id @default(autoincrement())
3
title String
4
content String
5
}
6
7
model Tag {
8
name String @id
9
}
  • Model์€ ํ…Œ์ด๋ธ” ์ •๋ณด๋ฅผ ์ •์˜ํ•œ๋‹ค.
  • Scalar, Relation, Type Modifier ๋“ฑ์„ ์‚ฌ์šฉํ•ด์„œ ํ…Œ์ด๋ธ”์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค

1.1.4 Enum

1
model User {
2
id Int @id @default(autoincrement())
3
email String @unique
4
name String?
5
role Role @default(USER)
6
}
7
8
enum Role {
9
USER
10
ADMIN
11
}
  • TypeORM์—์„œ ๋‹ค๋ค˜๋˜ enum ๊ฐœ๋…๊ณผ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
  • ํŠน์ • ๊ฐ’๋งŒ ์ž…๋ ฅ๋˜๋„๋ก ์œ ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค

1.1.5 Relations

1
model User {
2
id Int @id @default(autoincrement())
3
name String
4
posts Post[]
5
}
6
7
model Post {
8
id Int @id @default(autoincrement())
9
title String
10
userId Int
11
user 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 ํƒ€์ž…
StringText
BooleanBoolean
IntInteger
BigIntBigInt
FloatReal/Double Precision
DecimalNumeric
DateTimeTimestamp/ Timestamptz
JsonJSON/JSONB
BytesBYTEA

1.3 Attributes

์†์„ฑ์„ค๋ช…
@idPrimary Key
@default๊ธฐ๋ณธ๊ฐ’
@unique์œ ๋‹ˆํฌ/์œ ์ผ๋ฌด์ด ๊ฐ’
@relation๋ชจ๋ธ ๊ฐ„ ๊ด€๊ณ„
@mapํ…Œ์ด๋ธ”์˜ ๋‹ค๋ฅธ ์นผ๋Ÿผ์œผ๋กœ ๋งคํ•‘
@updatedAt์—…๋ฐ์ดํŠธ ์ˆœ๊ฐ„ DateTime ๊ธฐ๋ก
@@idComposite Primary Key
@@uniqueComposite Unique Key
@@indexIndex Keys

1.4 Prisma Client

1
genreator client {
2
provider = 'prisma-client-js'
3
}
1
$ npm install @prisma/client
2
$ prisma generate
  • generator์— prisma client ์ •์˜
  • @prisma/client ์„ค์น˜
  • prisma generate ์‹คํ–‰ (@prisma/client ์„ค์น˜์‹œ ์ž๋™ ์‹คํ–‰)

1.4.1 Prisma Client ์ž‘์—… ํ”Œ๋กœ์šฐ

nestjs-fastcam_46-1


1.4.2 Prisma Client ์ž‘๋™ ๋ฐฉ์‹

nestjs-fastcam_46-2


1.4.3 Prisma Create

1
const user = await prisma.user.create({
2
data: {
3
email: 'admin@codefactory.ai',
4
name: 'Code Factory',
5
},
6
})
1
const createMany = await prisma.user.createMany({
2
data: [
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
],
8
skipDuplicates: true, // ์›์˜ ์Šคํ‚ต๋จ
9
})

1.4.4 Prisma Read (1)

1
const user = await prisma.user.findUniquye({
2
where: { email: 'minji@codefactory.ai' },
3
})
1
const result = await prisma.user.findFirst({
2
where: {
3
email: { endsWith: 'codefactory.ai' },
4
},
5
})

1.4.5 Prisma Read (2)

1
const user = await prisma.user.findMany({
2
where: {
3
email: { endsWith: 'codefactory.ai' },
4
},
5
})
1
const users = await prisma.user.findMany({
2
where: {
3
OR: [
4
{ name: { startsWith: 'E' } },
5
{
6
AND: {
7
profileViews: { gt: 0 },
8
role: { 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 ํ•„๋“œ ์„ ํƒํ•˜๊ธฐ

1
const getUser = await prisma.user.findUnique({
2
where: { id: 22 },
3
select: {
4
email: true,
5
name: true,
6
},
7
})

email๊ณผ name ์นผ๋Ÿผ๋งŒ ์„ ํƒ


1.5.2 Prisma Read Relation ํฌํ•จํ•˜๊ธฐ

1
const users = await prisma.user.findMany({
2
include: {
3
posts: {
4
select: { title: true },
5
},
6
},
7
})

user ๊ฐ’์— post ๊ด€๊ณ„ ํฌํ•จํ•ด์„œ ๋ฐ˜ํ™˜


1.5.3 Relation Filtering Some

1
const result = await prisma.user.findMany({
2
where: {
3
post: {
4
some: {
5
content: { contains: 'Code Factory' },
6
},
7
},
8
},
9
})

Code Factory๋ฅผ content์— ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” post๊ฐ€ ์กด์žฌํ•˜๋Š” user๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ด


1.5.4 Relation Filtering Every

1
const result = await prisma.user.findMany({
2
where: {
3
post: {
4
every: { published: true },
5
},
6
},
7
})

๊ด€๋ จ๋œ post์˜ published๊ฐ€ ๋ชจ๋‘ true์ธ user๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ด


1.5.5 Relation Filtering None

1
const result = await prisma.user.findMany({
2
where: {
3
post: {
4
none: { published: true },
5
},
6
},
7
})

๊ด€๋ จ๋œ post์˜ published๊ฐ€ ๋ชจ๋‘ true๊ฐ€ ์•„๋‹Œ User๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ด


1.5.6 Relation Filtering Is

1
const result = await prisma.user.findMany({
2
where: {
3
user: {
4
is: { name: 'Code Factory' },
5
},
6
},
7
})

name ํ•„๋“œ๊ฐ€ Code Factory์ธ post๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ด


1.5.7 Relation Filtering IsNot

1
const result = await prisma.user.findMany({
2
where: {
3
user: {
4
isNot: { name: 'Code Factory' },
5
},
6
},
7
})

name ํ•„๋“œ๊ฐ€ Code Factory๊ฐ€ ์•„๋‹Œ User๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ด


1.5.8 Update

1
const updateUser = await prisma.user.update({
2
where: { email: 'test@codefactory.ai' },
3
data: { name: '๋ฏผ์ง€' },
4
})

์‚ฌ์šฉ์ž์˜ name ํ•„๋“œ๋ฅผ โ€˜๋ฏผ์ง€โ€™๋กœ ๋ณ€๊ฒฝ


1.5.9 Delete

1
const deleteUser = await prisma.user.delete({
2
where: { email: 'test@codefactory.ai' },
3
})

email์ด test@codefactory.ai์ธ ์‚ฌ์šฉ์ž๋ฅผ ์‚ญ์ œ


1.5.10 Relationship One to One

1
model User {
2
id Int @id @default(autoincrement())
3
profile Profile @relation(fields: [profileId], references: [id])
4
profileId Int @unique // ํ•„์ˆ˜ (1:1์ด๋‹ˆ๊นŒใ…ฃ ๋‹น์—ฐํžˆ)
5
}
6
7
model Profile {
8
id Int @id @default(autoincrement())
9
user User? // nullable๋งŒ ๊ฐ€๋Šฅ
10
}
1
model User {
2
id Int @id @default(autoincrement())
3
profile Profile? @relation(fields: [profileId], references: [id])
4
profileId Int? @unique // Optional ์ƒ์„ฑ ๊ฐ€๋Šฅ
5
}
6
7
model Profile {
8
id Int @id @default(autoincrement())
9
user User?
10
}

1.5.11 Relationship One to Many

1
model User {
2
id Int @id @default(autoincrement())
3
posts Post[]
4
}
5
6
model Post {
7
id Int @id @default(autoincrement())
8
author User @relation(fields: [authorId], references: [id])
9
authorId Int
10
}

1.5.12 Relationship Many to Many

1
model Post {
2
id Int @id @default(autoincrement())
3
title String
4
categories CategoriesOnPosts[]
5
}
6
7
model Category {
8
id Int @id @default(autoincrement())
9
name String
10
posts CategoriesOnPosts[]
11
}
12
13
model CategoriesOnPosts {
14
post Post @relation(fields: [postId], references: [id])
15
postId Int
16
category Category @relation(fields: [categoryId], references: [id])
17
categoryId Int
18
assignedAt DateTime @default(now())
19
assignedBy String
20
@@id([postId, categoryId])
21
}
1
model Post {
2
id Int @id @default(autoincrement())
3
title String
4
categories Category[]
5
}
6
7
model Category {
8
id Int @id @default(autoincrement())
9
name String
10
posts Post[]
11
}

1.6 Aggregate Function

ํ•จ์ˆ˜์„ค๋ช…
_avgํ‰๊ท 
_count๊ฐฏ์ˆ˜
_sumํ•ฉ๊ณ„
_min์ตœ์†Œ ๊ฐ’
_max์ตœ๋Œ€ ๊ฐ’

1.6.1 Aggregate

1
const aggregations = await prisma.user.aggregate({
2
_avg: { age: true },
3
})

1.6.2 Raw Query

1
const result = await prisma.$queryRaw('SELECT * FROM User')

1.6.3 Migration

1
# prisma migrate dev > ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ ์ƒ์„ฑ (์ž๋™)
2
prisma migrate dev --name "add-new-field"
1
# prisma migrate deploy > ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ง„ํ–‰
2
prisma 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), VirtualProperty
  • Relationship : One to Many, Many to Many
  • Transaction

2.4.1 Mongoose (์—ฐ๊ฒฐํ•˜๊ธฐ)

1
const mongoose = require('mongoose')
2
3
async function connectDB() {
4
try {
5
await mongoose.connect('mongodb://localhost:27017/mydb')
6
console.log('MongoDB Connected')
7
} catch (err) {
8
console.error('Connection Error:', err)
9
}
10
}
11
12
connectDB()

2.4.2 Mongoose (Schema ์ •์˜ํ•˜๊ธฐ)

1
const userSchema = new mongoose.Schema({
2
name: String,
3
age: Number,
4
email: String,
5
interests: [String],
6
})
7
8
const User = mongoose.model('User', userSchema)
9
10
const newUser = new User({
11
name: 'Code Factory',
12
age: 25,
13
email: 'admin@codefactory.ai',
14
interests: ['reading', 'music'],
15
})

2.4.3 Mongoose (Create ์ž‘์—…ํ•˜๊ธฐ)

1
async function createUser() {
2
try {
3
const user = await User.create({
4
name: '๋ฏผ์ง€',
5
age: 21,
6
email: 'minji@codefactory.ai',
7
interests: ['dancing', 'singing'],
8
})
9
console.log('User created:', user)
10
} catch (err) {
11
console.error('Error creating user:', err)
12
}
13
}

2.4.4 Mongoose (Read ์ž‘์—…ํ•˜๊ธฐ)

1
async function findAllUsers() {
2
try {
3
const users = await User.find({})
4
console.log('User found:', users)
5
} catch (err) {
6
console.error('Error finding users:', err)
7
}
8
}

2.4.5 Mongoose (Update ์ž‘์—…ํ•˜๊ธฐ)

1
async function updateUser() {
2
try {
3
const updateUser = await User.updateOne(
4
{ email: '๋ฏผ์ง€' }, //
5
{ $set: { age: 22 } },
6
)
7
console.log('User updated:', updateUser)
8
} catch (err) {
9
console.error('Error updating user:', err)
10
}
11
}

2.4.6 Mongoose (Delete ์ž‘์—…ํ•˜๊ธฐ)

1
async function deleteUser() {
2
try {
3
const deleteUser = await User.deleteOne({ name: '๋ฏผ์ง€' })
4
console.log('User deleted:', deleteUser)
5
} catch (err) {
6
console.error('Error deleting user:', err)
7
}
8
}

2.4.7 Mongoose (Populate ์œ ์‚ฌ Join)

1
const userSchema = new mongoose.Schema({
2
name: String,
3
age: Number,
4
email: String,
5
interests: [String],
6
})
7
8
const postSchema = new mongoose.Schema({
9
title: String,
10
author: {
11
type: mongoose.Schema.Types.ObjectId,
12
ref: 'User',
13
},
14
})
15
16
async function findPostsWithAuthors() {
17
try {
18
const posts = await Post.find().populate('author').exec()
19
console.log('Posts & authors:', posts)
20
} catch (err) {
21
console.error('Error : ', err)
22
}
23
}

2.4.8 Mongoose (Middleware Hook)

1
userSchema.pre('save', function (next) {
2
console.log('Saving user:', this.name)
3
next()
4
})
5
6
const 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

1
const mongoose = require('mongoose')
2
3
const profileSchema = new mongoose.Schema({
4
bio: String,
5
website: String,
6
location: String,
7
})
8
9
const userSchema = new mongoose.Schema({
10
name: String,
11
email: String,
12
profile: {
13
type: mongoose.Schema.Types.ObjectId,
14
ref: 'Profile',
15
},
16
})
1
const userSchema = new mongoose.Schema({
2
name: String,
3
email: String,
4
profile: {
5
bio: String,
6
website: String,
7
location: String,
8
},
9
})

2.5.2 One to Many

1
const commentSchema = new mongoose.Schema({
2
body: String,
3
date: Date,
4
postId: {
5
type: mongoose.Schema.Types.ObjectId,
6
ref: 'Post',
7
},
8
})
9
10
const postSchema = new mongoose.Schema({
11
title: String,
12
content: String,
13
comments: [
14
{
15
type: mongoose.Schema.Types.ObjectId,
16
ref: 'Comment',
17
},
18
],
19
})

2.5.3 Many to Many

1
const roleSchema = new mongoose.Schema({
2
name: String,
3
users: [
4
{
5
type: mongoose.Schema.Types.ObjectId,
6
ref: 'User',
7
},
8
],
9
})
10
11
const userSchema = new mongoose.Schema({
12
name: String,
13
roles: [
14
{
15
type: mongoose.Schema.Types.ObjectId,
16
ref: 'Role',
17
},
18
],
19
})

2.5.4 Mongoose (Transaction)

1
const session = await mongoose.startSession()
2
session.startTransaction()
3
4
try {
5
const user = new User({ name: '๋ฏผ์ง€', email: 'minji@codefactory.ai' })
6
await user.save({ session })
7
8
const post = new Post({ title: "Minji's Post", author: user._id })
9
await post.save({ session })
10
11
await session.commitTransaction() // ์ปค๋ฐ‹
12
session.endSession() // ์„ธ์…˜ ์ข…๋ฃŒ
13
} catch (error) {
14
await session.abortTransaction() // ๋กค๋ฐฑ
15
session.endSession()
16
throw error
17
}