몽고디비 모델링, 자주사용하는 연산자 정리

몽고디비(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
댓글을 사용할 수 없습니다.