MongoDB

MongoDB 쿼리 작성법과 최적화

코샵 2024. 12. 3. 11:02
반응형

소개

MongoDB는 강력한 쿼리 기능을 제공하는 NoSQL 데이터베이스입니다. 이번 글에서는 MongoDB의 다양한 쿼리 작성법과 실전 활용 방법을 자세히 알아보겠습니다.

기본 CRUD 쿼리

데이터 조회 (Read)

// 기본 조회
db.users.find()  // 모든 사용자 조회
db.users.findOne()  // 첫 번째 사용자 조회

// 조건 조회
db.users.find({ age: 30 })  // 나이가 30인 사용자
db.users.find({ name: "John" })  // 이름이 John인 사용자

// 특정 필드만 조회
db.users.find(
    { age: 30 },
    { name: 1, email: 1, _id: 0 }  // name과 email만 조회 (_id 제외)
)

데이터 생성 (Create)

// 단일 문서 삽입
db.users.insertOne({
    name: "John Doe",
    email: "john@example.com",
    age: 30
})

// 다중 문서 삽입
db.users.insertMany([
    {
        name: "Jane Doe",
        email: "jane@example.com",
        age: 28
    },
    {
        name: "Bob Smith",
        email: "bob@example.com",
        age: 35
    }
])

데이터 수정 (Update)

// 단일 문서 수정
db.users.updateOne(
    { name: "John Doe" },  // 조건
    { $set: { age: 31 } }  // 수정할 내용
)

// 다중 문서 수정
db.users.updateMany(
    { age: { $lt: 30 } },  // 30세 미만
    { $inc: { age: 1 } }   // 나이 1 증가
)

// 문서 교체
db.users.replaceOne(
    { name: "John Doe" },
    {
        name: "John Smith",
        email: "john.smith@example.com",
        age: 31
    }
)

데이터 삭제 (Delete)

// 단일 문서 삭제
db.users.deleteOne({ name: "John Doe" })

// 다중 문서 삭제
db.users.deleteMany({ age: { $lt: 25 } })

// 컬렉션 전체 삭제
db.users.deleteMany({})

고급 쿼리 연산자

비교 연산자

// $eq: 같음
db.users.find({ age: { $eq: 30 } })

// $ne: 같지 않음
db.users.find({ age: { $ne: 30 } })

// $gt, $gte: 초과, 이상
db.users.find({ age: { $gt: 30 } })   // 30 초과
db.users.find({ age: { $gte: 30 } })  // 30 이상

// $lt, $lte: 미만, 이하
db.users.find({ age: { $lt: 30 } })   // 30 미만
db.users.find({ age: { $lte: 30 } })  // 30 이하

// $in: 배열 안의 값과 일치
db.users.find({ age: { $in: [25, 30, 35] } })

// $nin: 배열 안의 값과 불일치
db.users.find({ age: { $nin: [25, 30, 35] } })

논리 연산자

// $and: 모든 조건 만족
db.users.find({
    $and: [
        { age: { $gte: 25 } },
        { age: { $lte: 35 } }
    ]
})

// $or: 하나 이상의 조건 만족
db.users.find({
    $or: [
        { age: { $lt: 25 } },
        { age: { $gt: 35 } }
    ]
})

// $not: 조건 불만족
db.users.find({
    age: { $not: { $eq: 30 } }
})

// $nor: 모든 조건 불만족
db.users.find({
    $nor: [
        { age: 25 },
        { name: "John" }
    ]
})

요소 연산자

// $exists: 필드 존재 여부
db.users.find({ email: { $exists: true } })

// $type: 필드 타입 검사
db.users.find({ age: { $type: "number" } })

배열 연산자

// $all: 모든 요소 포함
db.users.find({
    interests: { $all: ["reading", "music"] }
})

// $elemMatch: 배열 요소 매칭
db.users.find({
    scores: { 
        $elemMatch: { 
            $gt: 80,
            $lt: 90 
        }
    }
})

// $size: 배열 크기
db.users.find({
    interests: { $size: 3 }
})

집계 파이프라인

기본 집계

// $match: 문서 필터링
db.users.aggregate([
    {
        $match: {
            age: { $gte: 25 }
        }
    }
])

// $group: 그룹화
db.users.aggregate([
    {
        $group: {
            _id: "$age",
            count: { $sum: 1 },
            avgScore: { $avg: "$score" }
        }
    }
])

// $sort: 정렬
db.users.aggregate([
    {
        $sort: {
            age: -1,  // 내림차순
            name: 1   // 오름차순
        }
    }
])

고급 집계

// $lookup: 조인
db.orders.aggregate([
    {
        $lookup: {
            from: "users",
            localField: "userId",
            foreignField: "_id",
            as: "userInfo"
        }
    }
])

// $project: 필드 선택/변환
db.users.aggregate([
    {
        $project: {
            fullName: {
                $concat: ["$firstName", " ", "$lastName"]
            },
            age: 1,
            _id: 0
        }
    }
])

// $unwind: 배열 풀기
db.users.aggregate([
    {
        $unwind: "$interests"
    }
])

인덱스와 쿼리 최적화

인덱스 생성

// 단일 필드 인덱스
db.users.createIndex({ age: 1 })

// 복합 인덱스
db.users.createIndex(
    { age: 1, name: 1 }
)

// 유니크 인덱스
db.users.createIndex(
    { email: 1 },
    { unique: true }
)

쿼리 성능 분석

// 실행 계획 확인
db.users.find({ age: 30 }).explain()

// 쿼리 성능 통계
db.users.find({ age: 30 }).explain("executionStats")

실전 활용 예제

페이지네이션

// skip과 limit 사용
db.users.find()
    .skip(20)    // 처음 20개 건너뛰기
    .limit(10)   // 10개만 가져오기

텍스트 검색

// 텍스트 인덱스 생성
db.articles.createIndex({ content: "text" })

// 텍스트 검색
db.articles.find({
    $text: {
        $search: "mongodb database",
        $caseSensitive: false
    }
})

지리공간 쿼리

// 지리공간 인덱스 생성
db.places.createIndex({ location: "2dsphere" })

// 반경 내 검색
db.places.find({
    location: {
        $near: {
            $geometry: {
                type: "Point",
                coordinates: [127.0, 37.5]  // 경도, 위도
            },
            $maxDistance: 1000  // 미터 단위
        }
    }
})

마치며

MongoDB의 쿼리는 매우 유연하고 강력합니다. 기본적인 CRUD 연산부터 복잡한 집계 파이프라인까지, 상황에 맞는 적절한 쿼리를 작성할 수 있습니다. 성능 최적화를 위해서는 인덱스를 적절히 활용하고, 실행 계획을 분석하는 것이 중요합니다.