Why Another MongoDB Blog? Pt 2

Christopher Michael Clark
8 min readAug 9, 2021

Performing read actions on a MongoDB database collection using shell commands

Intro

In Part 1, we did a very high-level review of the differences between relational databases and document databases. In Part 2 we are going to be much more hands-on. We start by setting up a MongoDB Atlas database with seeded data that we can query. Next, we will install the MongoDB Shell. This CLI will allow us to send queries directly to our databases from our terminal. Finally, we will go over basic read action requests and how to format them.

Setting Up the Database with Seeded Data

If you wish to follow along, you will need a MongoDB Atlas account set up. If not, skip ahead to Querying Your Collections. This link will send you to the MongoDB ‘Get Started Free’ page to register. You can sign up for free or log in with an existing Google account. In order to provide comprehensive instructions I’d practically have to copy theirs word-for-word, so I’d rather just let them do that lifting. Before continuing, switch tabs and get that account set up, and then come back.

If you followed their instructions fully, you should have set up your MongoDB database, created a database user, and granted network access to your local IP (or just allow any since users still need passwords to access the DB). Navigate to the Database Deployments dashboard using their menu on the left, and then select ‘Browse Collections’ (Fig 1.1).

Fig 1.1: Database Deployments dashboard

This should lead you to a message that looks something like Fig 1.2. Follow the prompt to ‘Load a Sample Dataset’, and then go get a cup of coffee or tea or whatever your beverage of choice. I’ve done this a few times at different times of the day, and it always seems to take a couple minutes.

Fig 1.2: Collections panel sample dataset prompt

Okay. Great. Databases loaded. Your Collections menu should look like Fig 1.3 below. We are now ready to connect to our database.

Fig 1.3: MongoDB sample data loaded

Connecting to Your Cluster

MongoDB Atlas offers three possible ways to connect to your database cluster. You can connect with the MongoDB Shell via your terminal, you can connect your application directly, or you can connect using MongoDB Compass.

MongoDB Shell is a CLI that allows you to query your collections directly from your terminal. It allows the user to play around with the accessing and modifying the data with almost no overhead. All that is required is to install MongoDB Shell using yarn or npm. Connecting an application directly is exactly what it sounds like. MongoDB Compass is a downloadable GUI that allows the user to visualize the database locally to query and manipulate the data.

Our purpose here is to just practice querying and performing CRUD actions, so we are going to stick with the option with the least overhead: MongoDB Shell. Return to your Databases dashboard, and select ‘Connect’ as shown in Fig 2.1.

Fig 2.1 Databases dashboard

Next, you will select the top option, ‘Connect with the MongoDB Shell’ (Fig 2.2)

Fig 2.2 MongoDB Atlas connection options

Make sure you select the option for not having installed the Shell yet (Fig 2.3), and follow their instructions. If you Complete the process correctly, you should be able to copy/paste the connection string provided in Step 2 into your terminal to log in. You will be prompted to input your password, and once done, you will be connected to your cluster.

Fig 2.3 Setting up MongoDB Shell

Querying Your Collections

Logging In

Fig 3.1 Logging in to MongoDB Shell via the terminal

Okay, so let’s get started! Fig 3.1 shows what your terminal should look like after you’ve input the provided connection string along with your password. We are now ready to poke around our cluster.

Databases and Collections Overview

To take a quick look at which databases are available to you, simply input the command show dbs(Fig 3.2). The database will be listed for you along with their respective sizes.

Fig 3.2 Show the collections

To select a database, input the command use <collection name>(Fig 3.3). You will be notified that you have been switched to that database, and the command line indicates which database you are currently browsing.

Fig 3.3 Selecting a database

Each database will have its own list of collections available. Some databases may only have one collection, others multiple. As with viewing the databases, input the command show collections to see what is available (Fig 3.4).

Fig 3.4 Showing available collections

Making Queries

So far, we have connected to our database cluster, viewed the available databases, entered a database, and viewed the database’s collections. Now let’s make our first real query. The syntax for querying a collection is very simple: db.<collection name>.<query method>. Every query will begin this way. Let’s start with something simple. How many restaurants are in the collection? Input db.restaurants.count() to find out (Fig 3.5).

Fig. 3.5 Counting the restaurants

Wow! That is a bit more than I expected for a sample data set, but this gives us a ton to work with. In order to make queries it helps to know how the data is structured in each document. We can use the .find() method to search the collection. The method allows for parameters to be passed in, and if you pass no parameters the return will be every document in the collection. Since ours is slightly over 25,000 documents, it might be best to limit the search. We can chain our search with added methods, and in this case we will use .limit() with a parameter of 1 (Fig 3.6). We could also limit the search by using .findOne() instead of .find().

Fig 3.6 A single document returned after limiting the search.

Awesome! Something recognizable as a data entry. Our document has a document id, an address, a borough, a cuisine, grades, a name, and a restaurant id. In Part 1, we discussed how documents are laid out; they look and function like JSON objects. So, let’s treat them as such.

Querying with Parameters

Passing parameters with MongoDB queries should feel like second-nature to even a novice coder. Use the .find() method, and populate the parameters document with a {<field>: '<value>'}. In our case, we are going to search for restaurants that serve American cuisine. HOWEVER, since we have 25k+ restaurants in the database, let’s do a quick count by tacking on the .count() method again (Fig 3.7).

Fig 3.7 Filtering restaurants by cuisine

As suspected, more than we want. Again, let’s use .limit() to limit our results to 3 (Fig 3.8).

Fig 3.8 Limiting our results again

Awesome! You should now see the first three results in the database that match our search parameters. Each document should look similar to the result in Fig 3.6.

Let’s say we don’t need all that information though. What if we only wanted the names of the first five restaurants that offer American cuisine? We still use .limit(5), but we add something else to the .find() parameters. We still include the parameters document, but we follow that with a projection document; a document that describes precisely which fields we want returned.

In Fig 3.9, see still filter by cuisine with the parameters document. The second document, the projection document, is describing exactly which fields we want returned. In a default .find() query, every field in the document is returned. Only the fields listed in the projection doc, which carry values of 1, are returned. By default, every document comes with it’s own _id field so, if we only want the name we have to explicitly remove the doc’s _id.

Fig 3.9 Using .find() with parameters document and a projection document

Perfect. A list of five restaurants that serve American cuisine (Fig 3.10). This is cool and all, but it’s hardly useful to a user. What is the likelihood that the first five American cuisine restaurants in the collection merit any relevance to the user? Very slim. Why don’t we modify our search a bit and see what turns up?

Fig 3.10 Restaurants with only the name field in the projection doc

Usually when someone is looking for a restaurant it should most likely be nearby. To achieve this, we are going to search by zipcode. If we look back at Fig 3.6 we see that there is a zipcode field, but it is nested inside the address doc, which is embedded in the restaurant doc. An initial attempt of sending {zipcode: '11224'} would result in a failed query. We just need to modify the search slightly. This is done by passing the field as a string also, and using dot-notation to reference the subfield (Fig 3.11).

Fig 3.11 Querying a collection and filtering the results by a subfield’s value

These are the restaurants that exist in Brooklyn, NY in the 11224 zip code. By changing our parameter and projection documents we, can see how easy it is to return the exact data we need, formatted in a usable way. If we only need restaurant names, why send all the extra information along with it, right?

Fig 3.12 All the restaurants in the 11224 zip code (according to our db)

Summary

Okay, admittedly Part 2 became a bit longer than I intended. We signed up for MongoDB Atlas, seeded some data, installed the MongoDB Shell, and did some basic database collection searching. Not bad for one blog. However, we are just getting started.

In terms of CRUD (create, read, update, delete), we’ve only covered 25% of the possibilities. In Part 3 we are going to dive into the remaining three by connecting a Next.js app to our cluster and sending create, update, and delete requests directly from it instead of from our terminal.

References

--

--