What is nested collection in mongodb?

Learn the $elemMatch operator in MongoDB

MongoDB is an open-source document-oriented NoSQL database. We have introduced how to use mongosh to run basic CRUD commands in the console. Besides, we have also introduced how to use MongoDB Atlas to host your MongoDB server and data. In this post, we will take a step further and learn advanced MongoDB queries for nested documents using the $elemMatch operator from practical examples. We will still use mongosh to run the queries in the console so you don’t need to install anything additionally. However, you can use a graphical IDE for MongoDB if you prefer to work in a visual environment.

What is nested collection in mongodb?

Image from Pixabay.

Before we start this advanced journey, we should have a MongoDB server available. You can use Docker to start a MongoDB server in a container, or use MongoDB Atlas to start one that is hosted and maintained by Atlas. For simplicity, we will use a Docker container in this post, but you are free to choose the one you prefer. The commands to start a Docker container for MongoDB is:

$ docker network create mongo-net$ docker run --detach --network mongo-net --name mongo-server \
--env MONGO_INITDB_ROOT_USERNAME=admin \
--env MONGO_INITDB_ROOT_PASSWORD=pass \
--env MONGO_INITDB_ROOT_DATABASE=admin \
--volume mongo-data:/data/db \
--publish 27017:27017 \
mongo:5.0.6

You can install mongosh on your computer, or use the one coming together with the Docker container:

$ docker exec -it mongo-server bash
$ mongosh "mongodb://admin:pass@localhost:27017"

Now we can start to work with the MongoDB database using mongosh. If this is the first time you work mongosh, it’s recommended you check this introductory post first so you won’t get lost in the advanced queries.

The data we will use in this post is some product data for an online shop of laptops, as demonstrated in the post for Elasticsearch. You can download this JSON file to get the raw data that will be used.

If you use the mongosh inside the Docker container like me, you need to copy the JSON file into the container:

$ docker cp ./laptops_demo_for_mongodb.json mongo-server:/

And if you use the monosh installed on your computer, you need to have this JSON file in your current working directory. Then we can load this file and insert all the documents into a collection:

Key points for the code above:

  • We use use products to declare a MongoDB database called products, which will be created when a document is inserted into a collection in it.
  • The JSON data is loaded by the require command. And the loaded data is in a format that can be used by the insertMany() method directly. The laptops data is inserted into a collection called laptops.
  • The countDocuments() is used to check the number of documents in the collection and the findOne() method is used to show the first document in the collection.

Now the data is ready, we can begin to write some queries for it.

As we see, the laptop documents in the laptops collection have an attributes field that is an array of embedded documents. It is more complex to query and update a field like this than simple non-nested fields.

First, let’s find all the laptops whose CPU is Intel Core i7–8550U. This should be pretty simple because the CPU is unambiguous:

Note that the nested field is queried with a dot notation and must be put in quotes. If you prefer to write queries spanning multiple lines with a graphical IDE, please refer to this post regarding the IDEs for MongoDB.

We should get the result we want because there is only one nested document in the attributes array that has the value for CPU models:

Now let’s find all the laptops that have a memory of 16GB. Intuitively, you may want to use a query like this:

When the above query is executed, it seems all the laptops whose memory is 16GB are returned:

However, this is where many beginners of MongoDB make mistakes and where some bugs are introduced into your code. If you enter “it” in mongosh to show more results or just scroll down close to the bottom of the result page with an IDE and check carefully, you will find something strange:

We get the laptops whose storage is 16GB as well with the query above! This is because the above query finds the documents where the attributes array has at least one embedded document that contains the field attribute_name equal to memory and at least one embedded document (but not necessarily the same embedded document) that contains the field attribute_value equal to 16GB.

Since all the attributes arrays have an embedded document whose attribute_name is memory, the query above gave use erroneous results. What we want is that both conditions should be satisfied for the same embedded document. To achieve this, we cannot query by dot notation as shown above but need to use the $elemMatch operator:

This time the laptops whose storage is 16GB but memory is not 16GB will not be returned. If you don’t believe it, you can count the number of documents that are returned by both queries:

Now let’s try an even more complex case and find all the laptops whose memory is 16GB and storage is 1TB. We would need to use the $and operator to specify the conditions for two nested documents, which is very similar to the usage of the bool and must keywords in Elasticsearch for the query of nested documents.

This query will return the result we want:

Note that even though the $and operator is the default one in MongoDB, it is mandatory here because we are querying the same field in two different conditions. Otherwise, we will only query by the second condition and will get incorrect results:

You will get one incorrect result in this case. If you try with other conditions, you will get more incorrect results.

Once you know how to query an array with nested documents, it should be fairly easy to update it. Note that the nested documents are ordered in the array and therefore you can access a nested document by the index position.

Let’s update the memory to 16GB for the laptop with _id equal to 1:

If we check this laptop now, its attributes should have been updated:

Here we use projection to just show the attributes field of the document:

Cheers! The nested document is updated successfully!

In this post, we have introduced how to query and update an array of nested documents in MongoDB. This is an advanced usage but is very common in practice. I’m sure you are fairly confident in working with this kind of issue in your work now.

Where is MongoDB nested field?

Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.

How do I create a nested query in MongoDB?

MongoDB Nested Query Match on a Nested Field You can use the dot notation (“field. nestedField”) to specify query criteria for fields in embedded/nested documents. For queries that use dot notation, fields and nested fields must be enclosed in double-quotes.

How do I query a nested object in MongoDB?

To specify a query condition on fields in an embedded/nested document, use dot notation ( "field. nestedField" ).

Can we join two collections in MongoDB?

Hi, Yes, you can join 2 collections with Aggregation Framework and $unionWith stage. Here are the docs with syntax and examples, so you can check how to do it.