If you're just starting to dabble with MongoDB, you've probably come to a point where your documents are looking a little complex. These documents might have gone from flat, relational-looking pieces of data to something with nested objects, nested arrays, and maybe even four or five more levels of nesting. So how do you query this data when it is a few layers deep?
In this short tutorial, we're going to look at dot notation within MongoDB and see how we can very quickly and easily filter our documents based on data that contains certain values in the nested fields.
When referring to dot notation, we’re talking about the separation of nested fields with a period character delimiter. For example:
root_field.nested_field_1.next_layer_nested_field_1For every layer of nesting, we just add a period character separating that layer when querying. We’ll see more thorough examples as we progress through the tutorial.
To be successful with this tutorial, you'll need to have a MongoDB instance deployed and configured. This means the expectation is that you're at a point where you're ready to start using MongoDB. You should also have at least a basic familiarity with querying collections in MongoDB. The documentation might be a good place to start, if you need help.
For this example, we'll be using the following data within a "dbinc" database and a "people" collection:
[
{
"name": "Nic Raboy",
"websites": [
{
"type": "other",
"name": "Portfolio",
"url": "https://www.nraboy.com"
},
{
"type": "social",
"name": "LinkedIn",
"url": "https://www.linkedin.com/in/nraboy"
}
],
"employment": {
"employer": "MongoDB",
"address": {
"street": "1633 Broadway",
"city": "New York",
"state": "New York",
"postal_code": 10019
}
}
},
{
"name": "Tony Kim",
"websites": [
{
"type": "social",
"name": "LinkedIn",
"url": "https://www.linkedin.com/in/hyung-kim/"
},
{
"type": "coding",
"name": "GitHub",
"url": "https://github.com/hjkmines"
}
],
"employment": {
"employer": "MongoDB",
"address": {
"street": "1633 Broadway",
"city": "New York",
"state": "New York",
"postal_code": 10019
}
}
}
]The above data represents two documents that have a fair amount of complexity because they have nested objects and arrays. As a fun fact, MongoDB supports more than 100 levels of nesting within BSON documents.
If you're planning to follow along, make sure these documents exist within your MongoDB instance.
We're going to start simple and slowly move into more complicated territory. The good news is that complicated here doesn't necessarily mean difficult.
Let's say that we wanted to find all people within our collection who work for MongoDB. We could execute a query that looks like the following:
use dbinc;
db.people.find({
"employment.employer": "MongoDB"
});In this example, employer exists as a nested field within the employment object. We can query against that field using dot notation, which is simply just fields separated by a period character. This would be no different than if we wanted to find all people who worked in New York. We could do something like the following:
use dbinc;
db.people.find({
"employment.address.state": "New York"
});We queried three levels into the document in the above query, but it worked without issue.
Now, let's take a look at working with that nested array of objects. There are a few ways to query, depending on what we'd like to do.
Let's say we wanted to return all people who have a "Portfolio" website listed. We could execute a query that looks like the following:
use dbinc;
db.people.find({
"websites.name": "Portfolio"
});The above query would return a single result because only one of the documents had a "Portfolio" listed. Notice that even though we have an array, dot notation still worked here. The fine print is that "Portfolio" must exist somewhere within that array at least once.
This is where things can get interesting...
Let's say that we want to further restrict the results that are being returned. We'd do this by adding more filter criteria, but when working with nested objects within arrays, things are a little different. Take the following, for example:
use dbinc;
db.people.find({
"websites.name": "Portfolio",
"websites.type": "social"
});In the above example, we're saying that we want results where both "Portfolio" and "social" exist in the array, but not necessarily the same object. We only get one result back because the "Tony Kim" document has "social", but not "Portfolio". If we needed results where both fields had to exist in the same object, we wouldn't be able to use dot notation for that.
While out of the scope for this particular tutorial, using the $elemMatch operator like this would get the job done:
use dbinc;
db.people.find(
{
"websites": {
"$elemMatch": {
"name": "Portfolio",
"type": "social"
}
}
}
);No results would be returned in the above scenario because our sample data doesn't have a matching name and type within the same object.
If you are working with arrays and you know the array index that you want to work with, you can continue to use dot notation. For example, take the following:
use dbinc;
db.people.find({
"websites.0.name": "Portfolio"
});The above query uses the index of the array that you want to match against. In this scenario, we are wanting to return all documents where the first item in the array as a name of "Portfolio".
While out of the scope of this tutorial, it is important to call out that dot notation isn’t just restricted to read-only queries. You can use dot notation like seen here in update operations, projections, and aggregation pipelines.
You just got a quick introduction to using dot notation within your MongoDB queries. We learned:
$elemMatch operator is needed if you want to match multiple fields within a single array object.The data in your MongoDB collections will likely not be flat, meaning at some point, you're probably going to have nested objects, nested arrays, nested arrays within objects, and any other combination of complexity. The good news is that MongoDB makes it easy to work with this information using the rich query API.
If you're not already using MongoDB, check out MongoDB Atlas or my other tutorial that demonstrates getting started with Docker.
This content first appeared on DataCamp.

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.