Project MongoDB Fields

MongoDBBeginner
Practice Now

Introduction

In this lab, you will learn how to use MongoDB projection to control which fields appear in your query results. Projection is a powerful feature that allows you to select specific fields to return, which can reduce the amount of data transferred over the network and improve query performance. You will practice including and excluding fields, projecting fields within nested documents, and using the aggregation framework to reshape the output. By the end of this lab, you will have a solid understanding of how to effectively use projection in your MongoDB queries.

This is a Guided Lab, which provides step-by-step instructions to help you learn and practice. Follow the instructions carefully to complete each step and gain hands-on experience. Historical data shows that this is a beginner level lab with a 100% completion rate. It has received a 93% positive review rate from learners.

Select Specific Fields with Projection

In this first step, you will learn the basics of projection by selecting only the specific fields you want to see in your query results. This is known as an "inclusive" projection.

First, open the MongoDB Shell. This interactive command-line interface is where you will run all your database commands for this lab.

mongosh

You are now inside the MongoDB Shell. Your terminal prompt will change to indicate you are connected. Let's switch to a new database named projectlab_database and insert some sample data. If the database doesn't exist, MongoDB will create it for you when you first store data.

use projectlab_database

Next, insert three documents into a collection named 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"
  }
]);

Now, let's query this collection. To return only the name and age fields for all documents, you add a projection document as the second argument to the find() method. In the projection document, you specify the fields to include with a 1. By default, the _id field is always returned. You can explicitly exclude it by setting its value to 0.

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

You should see the following output, which contains only the name and age fields for each user:

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

This technique is very useful for retrieving only the necessary data, which is especially important when working with large documents.

Exclude Specific Fields from Results

In addition to selecting which fields to include, you can also specify which fields to exclude. This is known as an "exclusive" projection and is useful when you want to see most fields but hide a few, such as sensitive or large ones.

You should still be in the mongosh shell with the projectlab_database selected.

To exclude fields, you set their value to 0 in the projection document. Let's run a query to fetch all user data but exclude the email and city fields.

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

The output will include all fields except for email and city. Notice that the _id field is still included by default.

[
  {
    _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'
  }
]

A key rule in projection is that you cannot mix inclusion (1) and exclusion (0) in the same projection document. The only exception to this rule is the _id field. You can explicitly exclude the _id field (_id: 0) even when including other fields, as you did in the previous step. You can also exclude it in an exclusive projection.

For example, to exclude email, city, and _id, you would run the following:

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

This query returns documents containing only the name, age, and job fields.

Project Fields in Nested Documents

Real-world data is often structured with nested documents and arrays. MongoDB's projection capabilities allow you to precisely select fields even when they are embedded deep within a document's structure.

First, let's clear the existing users collection and insert new documents that have a nested contact object and a skills array.

db.users.deleteMany({});

Now, insert the new data.

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"]
  }
]);

To project a field inside a nested document, you use "dot notation". For example, to select the user's name and their mobile phone number, you would specify "contact.phone.mobile": 1. Let's try projecting the name, email, and mobile phone number.

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

The result will preserve the nested structure for the selected fields:

[
  {
    "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" }
    }
  }
]

You can also project a portion of an array using the $slice operator. To get the name and only the first two skills for each user, run the following command:

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

The output will show each user with a skills array containing just two elements:

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

Reshape Output Fields with Aggregation

For more advanced transformations, such as renaming fields or creating new computed fields, the find() method's projection is not enough. Instead, you can use the aggregation framework, specifically the $project stage.

Let's prepare our data for this step. Clear the collection and insert users with salary information.

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"
  }
]);

The $project stage in an aggregation pipeline can reshape documents by adding new fields, renaming existing fields, or removing fields. To use it, you pass an array of stages to the aggregate() method.

To rename a field, you define a new field name and assign it the value of an existing field, prefixed with a $ sign. Let's rename name to fullName and age to yearsOld.

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

You can also create new fields based on calculations. Let's create a monthlySalary field by dividing the annual salary by 12, and a salaryTier field based on conditional logic using the $switch operator.

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
    }
  }
]);

The output will be a completely new document structure that you defined in the $project stage:

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

The $project stage gives you complete control over the final shape of your query results, enabling powerful data transformations directly within the database.

Summary

In this lab, you have learned how to effectively control the output of your MongoDB queries using projection. You started with the basics of including and excluding fields with the find() method. You then progressed to more advanced topics, such as using dot notation to project fields within nested documents and using the $slice operator to return a subset of an array. Finally, you explored the power of the aggregation framework's $project stage to completely reshape documents by renaming fields, creating new computed fields, and applying conditional logic. These skills are fundamental for writing efficient and precise queries in MongoDB.