MongoDB 필드 프로젝션

MongoDBBeginner
지금 연습하기

소개

이 랩에서는 MongoDB 프로젝션 (projection) 을 사용하여 쿼리 결과에 어떤 필드가 나타날지 제어하는 방법을 배우게 됩니다. 프로젝션은 반환할 특정 필드를 선택할 수 있게 해주는 강력한 기능으로, 네트워크를 통해 전송되는 데이터 양을 줄이고 쿼리 성능을 향상시킬 수 있습니다. 필드 포함 및 제외, 중첩 문서 내 필드 프로젝션, 그리고 aggregation framework 를 사용하여 출력 형태를 재구성하는 연습을 하게 됩니다. 이 랩이 끝날 때쯤이면 MongoDB 쿼리에서 프로젝션을 효과적으로 사용하는 방법에 대한 확실한 이해를 갖게 될 것입니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 100%입니다.학습자들로부터 93%의 긍정적인 리뷰율을 받았습니다.

프로젝션을 사용하여 특정 필드 선택

첫 번째 단계에서는 쿼리 결과에서 보고 싶은 특정 필드만 선택하는 프로젝션의 기본 사항을 배우게 됩니다. 이는 "포함 (inclusive)" 프로젝션으로 알려져 있습니다.

먼저 MongoDB Shell 을 엽니다. 이 대화형 명령줄 인터페이스에서 이 랩의 모든 데이터베이스 명령을 실행하게 됩니다.

mongosh

이제 MongoDB Shell 안에 있습니다. 연결되었음을 나타내도록 터미널 프롬프트가 변경됩니다. projectlab_database라는 새 데이터베이스로 전환하고 샘플 데이터를 삽입해 보겠습니다. 데이터베이스가 존재하지 않으면 MongoDB 는 데이터를 처음 저장할 때 자동으로 생성합니다.

use projectlab_database

다음으로 users라는 컬렉션에 세 개의 문서를 삽입합니다.

db.users.insertMany([
  {
    name: "John Doe",
    age: 30,
    email: "john.doe@example.com",
    city: "New York",
    job: "Software Engineer"
  },
  {
    name: "Jane Smith",
    age: 28,
    email: "jane.smith@example.com",
    city: "San Francisco",
    job: "Data Scientist"
  },
  {
    name: "Mike Johnson",
    age: 35,
    email: "mike.johnson@example.com",
    city: "Chicago",
    job: "Product Manager"
  }
]);

이제 이 컬렉션을 쿼리해 보겠습니다. 모든 문서에 대해 nameage 필드만 반환하려면 find() 메서드에 두 번째 인수로 프로젝션 문서를 추가합니다. 프로젝션 문서에서는 포함할 필드를 1로 지정합니다. 기본적으로 _id 필드는 항상 반환됩니다. 이를 0으로 설정하여 명시적으로 제외할 수 있습니다.

db.users.find({}, { name: 1, age: 1, _id: 0 });

각 사용자에 대해 nameage 필드만 포함하는 다음 출력이 표시됩니다.

[
  { "name": "John Doe", "age": 30 },
  { "name": "Jane Smith", "age": 28 },
  { "name": "Mike Johnson", "age": 35 }
]

이 기법은 필요한 데이터만 검색하는 데 매우 유용하며, 특히 대용량 문서를 다룰 때 중요합니다.

결과에서 특정 필드 제외

포함할 필드를 선택하는 것 외에도 제외할 필드를 지정할 수도 있습니다. 이는 "제외 (exclusive)" 프로젝션으로 알려져 있으며, 대부분의 필드를 보고 싶지만 민감하거나 큰 필드와 같이 일부 필드를 숨기고 싶을 때 유용합니다.

여전히 mongosh 쉘에 있고 projectlab_database가 선택된 상태여야 합니다.

필드를 제외하려면 프로젝션 문서에서 해당 필드의 값을 0으로 설정합니다. 모든 사용자 데이터를 가져오지만 emailcity 필드는 제외하는 쿼리를 실행해 보겠습니다.

db.users.find({}, { email: 0, city: 0 });

출력에는 emailcity를 제외한 모든 필드가 포함됩니다. _id 필드는 기본적으로 여전히 포함된다는 점에 유의하십시오.

[
  {
    _id: ObjectId("..."),
    name: 'John Doe',
    age: 30,
    job: 'Software Engineer'
  },
  {
    _id: ObjectId("..."),
    name: 'Jane Smith',
    age: 28,
    job: 'Data Scientist'
  },
  {
    _id: ObjectId("..."),
    name: 'Mike Johnson',
    age: 35,
    job: 'Product Manager'
  }
]

프로젝션의 주요 규칙은 동일한 프로젝션 문서에서 포함 (1) 과 제외 (0) 를 혼합할 수 없다는 것입니다. 이 규칙의 유일한 예외는 _id 필드입니다. 이전 단계에서 수행한 것처럼 다른 필드를 포함하는 경우에도 _id 필드를 명시적으로 제외 (_id: 0) 할 수 있습니다. 제외 프로젝션에서도 이를 제외할 수 있습니다.

예를 들어, email, city, _id를 제외하려면 다음을 실행합니다.

db.users.find({}, { email: 0, city: 0, _id: 0 });

이 쿼리는 name, age, job 필드만 포함하는 문서를 반환합니다.

중첩 문서의 필드 프로젝션

실제 데이터는 종종 중첩된 문서와 배열로 구조화됩니다. MongoDB 의 프로젝션 기능을 사용하면 문서 구조 깊숙이 포함된 필드도 정확하게 선택할 수 있습니다.

먼저 기존 users 컬렉션을 삭제하고 중첩된 contact 객체와 skills 배열을 가진 새 문서를 삽입해 보겠습니다.

db.users.deleteMany({});

이제 새 데이터를 삽입합니다.

db.users.insertMany([
  {
    name: "John Doe",
    contact: {
      email: "john.doe@example.com",
      phone: {
        mobile: "123-456-7890",
        work: "987-654-3210"
      }
    },
    skills: ["JavaScript", "MongoDB", "React"]
  },
  {
    name: "Jane Smith",
    contact: {
      email: "jane.smith@example.com",
      phone: {
        mobile: "234-567-8901",
        work: "876-543-2109"
      }
    },
    skills: ["Python", "Data Science", "Machine Learning"]
  }
]);

중첩된 문서 내의 필드를 프로젝션하려면 "점 표기법 (dot notation)"을 사용합니다. 예를 들어, 사용자의 name과 모바일 전화번호를 선택하려면 "contact.phone.mobile": 1을 지정합니다. name, email, mobile 전화번호를 프로젝션해 보겠습니다.

db.users.find(
  {},
  {
    name: 1,
    "contact.email": 1,
    "contact.phone.mobile": 1,
    _id: 0
  }
);

결과는 선택된 필드에 대해 중첩된 구조를 유지합니다.

[
  {
    "name": "John Doe",
    "contact": {
      "email": "john.doe@example.com",
      "phone": { "mobile": "123-456-7890" }
    }
  },
  {
    "name": "Jane Smith",
    "contact": {
      "email": "jane.smith@example.com",
      "phone": { "mobile": "234-567-8901" }
    }
  }
]

$slice 연산자를 사용하여 배열의 일부를 프로젝션할 수도 있습니다. 각 사용자의 name과 처음 두 개의 스킬만 가져오려면 다음 명령을 실행합니다.

db.users.find({}, { name: 1, skills: { $slice: 2 }, _id: 0 });

출력에는 각 사용자의 skills 배열에 두 개의 요소만 포함됩니다.

[
  { "name": "John Doe", "skills": ["JavaScript", "MongoDB"] },
  { "name": "Jane Smith", "skills": ["Python", "Data Science"] }
]

Aggregation 을 사용한 출력 필드 재구성

필드 이름 변경 또는 새 계산 필드 생성과 같은 더 고급 변환의 경우 find() 메서드의 프로젝션만으로는 충분하지 않습니다. 대신 집계 프레임워크, 특히 $project 단계를 사용할 수 있습니다.

이 단계를 위해 데이터를 준비해 보겠습니다. 컬렉션을 삭제하고 급여 정보가 있는 사용자를 삽입합니다.

db.users.deleteMany({});
db.users.insertMany([
  {
    name: "John Doe",
    age: 30,
    salary: 75000,
    department: "Engineering"
  },
  {
    name: "Jane Smith",
    age: 28,
    salary: 85000,
    department: "Data Science"
  },
  {
    name: "Mike Johnson",
    age: 35,
    salary: 95000,
    department: "Management"
  }
]);

집계 파이프라인의 $project 단계는 새 필드를 추가하거나, 기존 필드 이름을 변경하거나, 필드를 제거하여 문서를 재구성할 수 있습니다. 사용하려면 스테이지 배열을 aggregate() 메서드에 전달합니다.

필드 이름을 변경하려면 새 필드 이름을 정의하고 기존 필드 값 앞에 $ 기호를 붙여 할당합니다. namefullName으로, ageyearsOld로 변경해 보겠습니다.

db.users.aggregate([
  {
    $project: {
      fullName: "$name",
      yearsOld: "$age",
      _id: 0
    }
  }
]);

계산을 기반으로 새 필드를 만들 수도 있습니다. 연간 salary를 12 로 나누어 monthlySalary 필드를 만들고, $switch 연산자를 사용하여 조건부 논리를 기반으로 salaryTier 필드를 만들어 보겠습니다.

db.users.aggregate([
  {
    $project: {
      name: 1,
      monthlySalary: { $divide: ["$salary", 12] },
      salaryTier: {
        $switch: {
          branches: [
            { case: { $lt: ["$salary", 80000] }, then: "Junior" },
            { case: { $gte: ["$salary", 80000] }, then: "Senior" }
          ],
          default: "Unknown"
        }
      },
      _id: 0
    }
  }
]);

출력은 $project 단계에서 정의한 완전히 새로운 문서 구조가 됩니다.

[
  { "name": "John Doe", "monthlySalary": 6250, "salaryTier": "Junior" },
  {
    "name": "Jane Smith",
    "monthlySalary": 7083.333333333333,
    "salaryTier": "Senior"
  },
  {
    "name": "Mike Johnson",
    "monthlySalary": 7916.666666666667,
    "salaryTier": "Senior"
  }
]

$project 단계는 쿼리 결과의 최종 구조에 대한 완전한 제어를 제공하여 데이터베이스 내에서 직접 강력한 데이터 변환을 가능하게 합니다.

요약

이 실습에서는 프로젝션을 사용하여 MongoDB 쿼리의 출력을 효과적으로 제어하는 방법을 배웠습니다. find() 메서드를 사용하여 필드를 포함하고 제외하는 기본 사항부터 시작했습니다. 그런 다음 중첩된 문서 내의 필드를 프로젝션하기 위해 점 표기법 (dot notation) 을 사용하고 배열의 하위 집합을 반환하기 위해 $slice 연산자를 사용하는 것과 같은 고급 주제로 진행했습니다. 마지막으로 필드 이름을 변경하고, 새 계산 필드를 만들고, 조건부 논리를 적용하여 문서를 완전히 재구성하기 위해 집계 프레임워크의 $project 단계의 강력함을 탐구했습니다. 이러한 기술은 MongoDB 에서 효율적이고 정확한 쿼리를 작성하는 데 필수적입니다.