몽고디비 모델링, 자주사용하는 연산자 정리
몽고디비(MongoDB)와 관계형 데이터베이스(RDBMS) 간의 모델링 차이
관계형 데이터베이스에서는 보통 데이터를 여러 테이블에 나누어 저장합니다. 예를 들어, "사용자(User)"와 "주문(Order)"이라는 두 개의 테이블이 있다고 가정해보겠습니다.
User 테이블
user_id (Primary Key)
name
email
...
Order 테이블
order_id (Primary Key)
user_id (Foreign Key referencing User)
product_name
order_date
...
이러한 구조에서, 특정 사용자의 모든 주문을 조회하려면 두 테이블을 조인(join)해야 합니다. 이는 다음과 같은 SQL 쿼리로 표현될 수 있습니다.
SELECT u.name, o.product_name, o.order_date
FROM User u
JOIN Order o ON u.user_id = o.user_id
WHERE u.user_id = 1;
몽고디비(MongoDB)에서의 모델링
몽고디비에서는 데이터를 컬렉션(collection)에 문서(document) 형태로 저장합니다. 몽고디비에서는 두 개의 컬렉션을 사용하는 대신, 하나의 컬렉션에 데이터를 모두 넣을 수 있습니다.
{
"_id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"orders": [
{
"order_id": 101,
"product_name": "Laptop",
"order_date": "2024-08-01"
},
{
"order_id": 102,
"product_name": "Smartphone",
"order_date": "2024-08-02"
}
]
}
이 경우, 특정 사용자의 주문 정보를 조회할 때 조인이 필요하지 않습니다. 단일 문서로 모든 관련 데이터를 가져올 수 있습니다.
몽고디비에서는 관련된 데이터를 한 문서 안에 모두 포함시킬 수 있기 때문에, 조인 없이도 복잡한 구조의 데이터를 빠르게 조회할 수 있습니다.
몽고디비는 스키마리스(schema-less) 데이터베이스이므로, 데이터 구조를 유연하게 설계할 수 있으며, 필요한 경우 필드나 중첩된 구조를 쉽게 변경할 수 있습니다.
몽고디비에서 데이터를 쿼리할 때 find와 aggregate의 match 단계
1. find 메서드
find는 MongoDB에서 데이터를 조회할 때 가장 기본적인 메서드입니다. find 메서드를 사용하여 특정 조건에 맞는 문서를 찾을 수 있습니다.
// 컬렉션에서 name이 "John Doe"인 모든 문서를 찾기
db.collection.find({ name: "John Doe" })
// 컬렉션에서 age가 30 이상인 모든 문서를 찾기
db.collection.find({ age: { $gte: 30 } })
2. aggregate의 match 단계
aggregate 메서드는 몽고디비에서 데이터의 집계 작업을 수행할 때 사용됩니다.
// name이 "John Doe"이고 age가 30 이상인 문서를 필터링하는 집계 파이프라인
db.collection.aggregate([
{ $match: { name: "John Doe", age: { $gte: 30 } } }
])
MongoDB에서 배열 필드를 쿼리할 때 사용되는 연산자 $elemMatch
배열 내의 요소가 특정 조건을 만족하는지 검사하는 데 사용됩니다. 주로 배열의 각 요소가 객체일 때 유용합니다.
$elemMatch는 배열 필드에 대해 조건을 지정할 때 사용됩니다.
{
"name": "John",
"scores": [
{ "subject": "math", "score": 80 },
{ "subject": "history", "score": 90 },
{ "subject": "science", "score": 85 }
]
}
수학 점수가 80 이상이고, 과학 점수가 85 이상인 학생을 찾고 싶다고 가정하면 scores 배열에서 각 요소의 조건이 아니라 하나의 요소에서 subject가 "math"이고 score가 80 이상인지를 확인합니다.
db.students.find({
scores: {
$elemMatch: {
subject: "math",
score: { $gte: 80 }
}
}
})
$addFields는 MongoDB의 집계 프레임워크에서 사용되는 연산자 중 하나로, 기존 문서에 새로운 필드를 추가하거나 기존 필드를 수정하는 데 사용
$addFields의 기본 개념
- 새로운 필드 추가: 기존 문서에 계산된 값을 기반으로 새로운 필드를 추가
- 기존 필드 수정: 기존 필드를 참조하여 값을 변경하거나 업데이트
- 다양한 연산 사용: $addFields 내에서 여러 연산자($sum, $multiply, $concat, $ifNull 등)를 사용해 필드 값을 계산
db.collection.aggregate([
{
$addFields: {
newField: <expression>,
anotherNewField: <anotherExpression>,
existingField: <newExpression>
}
}
])
학생들의 성적 데이터베이스에서 수학과 과학 점수의 합계를 계산하여 새로운 필드 totalScore를 추가하는 예제
#데이터
{
"name": "Alice",
"math": 85,
"science": 90
}
#쿼리
db.students.aggregate([
{
$addFields: {
totalScore: { $sum: ["$math", "$science"] }
}
}
])
#결과
{
"name": "Alice",
"math": 85,
"science": 90,
"totalScore": 175
}
더 복잡한 파이프라인에서 $addFields 사용
#데이터
{
"name": "John",
"salary": 70000,
"bonus": 20000
}
#쿼리
db.employees.aggregate([
{
$addFields: {
totalCompensation: { $sum: ["$salary", "$bonus"] },
isHighEarner: { $gte: [{ $sum: ["$salary", "$bonus"] }, 100000] }
}
}
])
#결과
{
"name": "John",
"salary": 70000,
"bonus": 20000,
"totalCompensation": 90000,
"isHighEarner": false
}
부적절하게 사용할 경우 몇 가지 단점
- $addFields는 각 문서에 대해 새로운 필드를 계산하여 추가하기 때문에, 계산이 복잡할수록 더 많은 리소스를 소비
- 많은 필드 추가나 복잡한 연산이 포함된 $addFields를 반복적으로 사용하면, CPU와 메모리 사용이 급격히 증가
MongoDB에서 문자열을 정렬
숫자 정렬 (numericOrdering: true 옵션)
numericOrdering 옵션을 사용하면 문자열 내의 숫자를 자연스럽게 정렬할 수 있습니다. 일반적인 사전순 정렬에서는 "10"이 "2"보다 먼저 오지만, numericOrdering: true를 설정하면 "2"가 "10"보다 앞에 오도록 정렬시킬 수 있습니다.
db.collection.find().sort({ name: 1 }).collation({ locale: "en", numericOrdering: true });
$unwind는 MongoDB의 집계 파이프라인에서 사용되는 연산자
하나의 문서에 있는 배열 필드의 각 요소가 개별 문서로 확장됩니다.
{
"_id": 1,
"name": "John",
"hobbies": ["reading", "swimming", "cycling"]
},
{
"_id": 2,
"name": "Alice",
"hobbies": ["painting", "dancing"]
}
이 데이터를 hobbies 필드를 기준으로 $unwind 연산자를 사용하여 확장하면 다음과 같은 결과가 나옵니다.
db.collection.aggregate([
{ $unwind: "$hobbies" }
])
{
"_id": 1,
"name": "John",
"hobbies": "reading"
},
{
"_id": 1,
"name": "John",
"hobbies": "swimming"
},
{
"_id": 1,
"name": "John",
"hobbies": "cycling"
},
{
"_id": 2,
"name": "Alice",
"hobbies": "painting"
},
{
"_id": 2,
"name": "Alice",
"hobbies": "dancing"
}
혼합된 문서에서 특정 필드를 제외하고 특정 정보만 가져오고 싶을 때, $project 연산자를 사용
이 데이터에서 transactionId, transactionAmount, transactionDate와 같은 트랜잭션 관련 필드를 제외하고 어카운트 정보만 가져오고 싶다고 가정해보겠습니다.
{
"_id": 1,
"accountId": "A12345",
"accountName": "John Doe",
"balance": 1000,
"transactionId": "T98765",
"transactionAmount": 100,
"transactionDate": "2024-08-01"
},
{
"_id": 2,
"accountId": "A67890",
"accountName": "Jane Smith",
"balance": 2500,
"transactionId": "T54321",
"transactionAmount": 200,
"transactionDate": "2024-08-02"
}
$project 연산자로 특정 필드 제외하기
$project 연산자를 사용하여 트랜잭션 관련 필드를 제외하고 어카운트 정보만 남기는 쿼리를 작성합니다.
db.collection.aggregate([
{
$project: {
transactionId: 0,
transactionAmount: 0,
transactionDate: 0
}
}
])
결과
{
"_id": 1,
"accountId": "A12345",
"accountName": "John Doe",
"balance": 1000
},
{
"_id": 2,
"accountId": "A67890",
"accountName": "Jane Smith",
"balance": 2500
}
추가 쿼리 작성
예를 들어, 잔액(balance)이 1500 이상인 어카운트만 필터링하고 싶다면, 다음과 같이 쿼리를 작성할 수 있습니다.
db.collection.aggregate([
{
$project: {
transactionId: 0,
transactionAmount: 0,
transactionDate: 0
}
},
{
$match: {
balance: { $gte: 1500 }
}
}
])
최종 결과
이 쿼리의 결과는 다음과 같이 잔액이 1500 이상인 어카운트 정보만 반환됩니다.
{
"_id": 2,
"accountId": "A67890",
"accountName": "Jane Smith",
"balance": 2500
}
'IT' 카테고리의 다른 글
[VMware Tanzu] Spring Boot 밋업 with Josh Long (0) | 2024.09.29 |
---|---|
Spring Batch 5 migration guide (0) | 2024.09.01 |
가상 면접 사례로 배우는 대규모 시스템 설계 기초 2장 - 개략적인 규모 추정 (0) | 2024.07.28 |
가상 면접 사례로 배우는 대규모 시스템 설계 기초 1장 - 사용자 수에 따른 규모 확장성 (2) (0) | 2024.07.21 |
가상 면접 사례로 배우는 대규모 시스템 설계 기초 1장 - 사용자 수에 따른 규모 확장성 (1) (0) | 2024.07.14 |
댓글
이 글 공유하기
다른 글
-
[VMware Tanzu] Spring Boot 밋업 with Josh Long
[VMware Tanzu] Spring Boot 밋업 with Josh Long
2024.09.29 -
Spring Batch 5 migration guide
Spring Batch 5 migration guide
2024.09.01 -
가상 면접 사례로 배우는 대규모 시스템 설계 기초 2장 - 개략적인 규모 추정
가상 면접 사례로 배우는 대규모 시스템 설계 기초 2장 - 개략적인 규모 추정
2024.07.28 -
가상 면접 사례로 배우는 대규모 시스템 설계 기초 1장 - 사용자 수에 따른 규모 확장성 (2)
가상 면접 사례로 배우는 대규모 시스템 설계 기초 1장 - 사용자 수에 따른 규모 확장성 (2)
2024.07.21