The author selected the Open Internet/Free Speech Fund to receive a donation as part of the Write for DOnations program.
Introduction
MongoDB is a persistent document-oriented database used to store and process data in the form of documents. As with other database management systems, MongoDB allows you to manage and interact with data through four fundamental types of
data operations: Restructuring operations, which
- involve writing
- Read
- operations Update, which change data that already exists in
- D elete operations, which permanently delete data from a database
data to the database.
operations, which query a database to retrieve data from it Date
a database
These four operations are collectively called CRUD operations
.
This tutorial describes how to create new MongoDB documents and then retrieve them to read their data. It also explains how to update data within documents, as well as how to delete documents when they are no longer needed.
Prerequisites
To follow this tutorial, you will need:
- A server with a normal, non-root user with sudo privileges, and a firewall configured with UFW. This tutorial was validated using a server running Ubuntu 20.04, and you can prepare your server by following this initial server setup tutorial for Ubuntu 20.04.
- MongoDB installed on your server. To set this up, follow our tutorial on How to Install MongoDB on Ubuntu 20.04.
- The MongoDB instance on your server is secured by enabling authentication and creating an administrative user. To protect MongoDB in this way, follow our tutorial on how to secure MongoDB in Ubuntu 20.04.
- Basic familiarity with the MongoDB shell used throughout this tutorial. To learn how to use the MongoDB shell, follow the tutorial How to use the MongoDB shell.
Step 1: Connect
to the MongoDB server
This guide involves using the MongoDB shell to interact with MongoDB. To follow and practice CRUD operations in MongoDB, you must first connect to a MongoDB database by opening the MongoDB shell.
If your MongoDB instance
is running on a remote server, SSH to that server from the local computer:
- ssh sammy@your_server_ip
Next, connect to the MongoDB installation by opening the MongoDB shell. Be sure to log in as a MongoDB user with privileges to write and read data. If you followed the MongoDB security tutorial as a prerequisite, you can connect as the administrative user you created in step 1 of that guide:
- mongo -u AdminSammy-p -authenticationDatabase admin
After providing the user’s password, the terminal prompt will change to a sign greater than (>). This means that the shell is now ready to accept commands for the MongoDB server it is connected to.
Now that you have connected to the MongoDB server using a MongoDB shell, you can move on to creating new documents.
Step 2 — Creating
documents
To have data that you can practice reading, updating, and deleting in the later steps of this guide, this step focuses on how to create data documents in
MongoDB.
Imagine you’re using MongoDB to create and manage a directory of famous historical landmarks around the world. This directory will store information such as the name of each monument, country, city and geographical location.
The documents in this
directory will follow a format similar to this example, representing The Pyramids of Giza: { “name”: “The Pyramids of
Giza”, “city”: “Giza”, “country”: “Egypt”, “gps”: { “lat”: 29.976480, “lng”: 31.131302 } } This
document, like all MongoDB documents, is written in BSON. BSON is a binary form of JSON, a human-readable data format. All data in BSON or JSON documents is represented as field-value pairs that take the form of a field: value.
This document consists of four fields. First is the name of the monument, followed by the city and country. All three fields contain strings. The last field, called gps, is a nested document detailing the GPS location of the monument. This location consists of a pair of latitude and longitude coordinates, represented by the lat and lng fields respectively, each of which has floating-point values.
Insert this document into a new collection named monuments by using the insertOne method. As the name suggests, insertOne is used to create individual documents, rather than creating multiple documents at once.
In the MongoDB shell, run the following operation
: db.monuments.insertOne( { “name”: “The pyramids of Giza”, “city”: “Giza”, “country”: “Egypt”, “gps”: { “lat”:
- 29.976480,
- lng”: 31.131302
- )
- insertOne method.
“
}
}
Note that you did not explicitly create the monument collection before running this
MongoDB allows you to run commands on non-existent collections freely, and missing collections are only created when the first object is inserted. Running this example insertOne() method will not only insert the document into the collection, but also create the collection automatically.
MongoDB will execute the insertOne method and insert the requested document representing the pyramids of Giza. The output of the operation will inform you that it was executed successfully and also provides the ObjectId that it automatically generated for the new
document: Output{ “acknowledged” : true, “insertedId” : ObjectId(“6105752352e6d1ebb7072647”) }
In MongoDB, each document within a collection must have a unique _id field that acts as the primary key. You can include the _id field and provide it with a value of your choice, as long as you make sure that the _id field of each document is unique. However, if a new document omits the _id field, MongoDB will automatically generate an object identifier (in the form of an ObjectId object) as the value for the _id field.
You can verify that the document
was inserted by checking the count of objects
in the monuments collection:
- db.monuments.count()
Since you have only inserted one document into this collection, the count method will return 1:
Output1 Inserting documents one
by one in this way would quickly become tedious if you want to create multiple documents. MongoDB provides the insertMany method that you can use to insert multiple documents in a single operation.
Run the following example command, which uses the insertMany method to insert six additional famous monuments into the monument collection: db.monuments.insertMany
([ {“name”: “The Valley of the Kings”, “city”: “Luxor”, “country”: “Egypt”, “gps”: { “lat”: 25.746424, “lng”: 32.605309 }}, {“name”: “Arc de Triomphe”, “city”: “Paris”, “country”: “France”, “gps”: { “lat”:
- 48.873756, “lng”: 2.294946
- },
- {“name”
- 40.431908, “lng”: 116.570374
- },
- {“name”: “The Statue of Liberty”, “city”: “New York”, “country”: “USA”, “gps”: { “lat”: 40.689247, “lng”: -74.044502 }}
- ]
}
: “The Eiffel Tower”, “city”: “Paris”, “country”: “France”, “gps”: { “lat”: 48.858093, “lng”: 2.294694 }}, {“name”: “Acropolis”, “city”: “Athens”, “country”: “Greece”, “gps”: { “lat”: 37.970833, “lng”: 23.726110 }}, {“name”: “The Great Wall of China”, “city”: “Huairou”, “country”: “China”, “gps”: { “lat”:
}
)
Note the square brackets ([ and ]) surrounding the six documents. These square brackets signify a series of documents. In square brackets, multiple objects can appear one after the other, delimited by commas. In cases where the MongoDB method requires more than one object, you can provide an array list of objects like this.
MongoDB will respond with several object identifiers, one for each of the newly inserted objects:
Output{ “acknowledged” : true, “insertedIds” : [ ObjectId(“6105770952e6d1ebb7072648”), ObjectId(“6105770952e6d1ebb7072649”), ObjectId(“6105770952e6d1ebb707264a”), ObjectId(“6105770952e6d1ebb707264b”), ObjectId(“6105770952e6d1ebb707264c”), ObjectId(“6105770952e6d1ebb707264d”) ] }
You can verify that the documents were inserted by checking the count of objects in the monuments collection: db.monuments.count
- ()
After adding these six new documents, the expected output of this command is 7:
Output7
With that, you have used two separate insertion methods to create a series of documents representing various famous monuments. Next, you’ll read the data you just inserted with the MongoDB find() method.
Step 3 — Reading
documents
Now that your collection has some documents stored in it, you can query your database to retrieve these documents and read your data. This step first describes how to query all documents in a given collection, and then describes how to use filters to narrow down the list of retrieved documents.
After completing the previous step, you now have seven documents describing famous monuments inserted into the monument collection. You can retrieve all seven documents with a single operation using
the find() method:
- db.monuments.find()
This method, when used without arguments, does not apply any filtering and prompts MongoDB to return all available objects in the specified collection, monuments. MongoDB will return the following output
: Output{ “_id” : ObjectId(“6105752352e6d1ebb7072647”), “name” : “The pyramids of Giza”, “city” : “Giza”, “country” : “Egypt”, “gps” : { “lat” : 29.29.29.97648, “lng” : 31.131302 } } { “_id” : ObjectId(“6105770952e6d1ebb7072648”), “name” : “The Valley of the Kings”, “city” : “Luxor”, “country” : “Egypt”, “gps” : { “lat” : 25.746424, “lng” : 32.605309 } } { “_id” : ObjectId(“6105770952e6d1ebb7072649”), “name” : “Arc de Triomphe”, “city” : “Paris”, “country” : “France”, “gps” : { “lat” : 48.873756, “lng” : 2.294946 } } { “_id” : ObjectId(“6105770952e6d1ebb707264a”), “name” : “La Torre Eiffel”, “city” : “Paris”, “country” : “France”, “gps” : { “lat” : 48.”name” 48.48.858093, “lng” : 2.294694 } } { “_id” : ObjectId(“6105770952e6d1ebb707264b”), “name” : “Acropolis”, “city” : “Athens”, “country” : “Greece”, “gps” : { “lat” : 37.970833, “lng” : 23.72611 } } { “_id” : ObjectId(“6105770952e6d1ebb707264c”), “name” : “The Great Wall of China”, “city” : “Huairou”, “country” : “China”, “gps” : { “lat” : 40..40.0 431908, “lng” : 116.570374 } } { “_id” : ObjectId(“6105770952e6d1ebb707264d”), “name” : “The Statue of Liberty”, “city” : “New York”, “country” : “USA”, “gps” : { “lat” : 40.689247, “lng” : -74.044502 } }
The MongoDB shell prints all seven documents one by one and in their entirety. Note that each of these objects has a _id property that you did not define. As mentioned earlier, _id fields serve as the primary key of their respective documents and were created automatically by running the insertMany method in the previous step.
The default output of the MongoDB shell is compact, with the fields and values of each document printed on a single line. This can be difficult to read with objects that contain multiple fields or nested documents, in particular.
To make the output of the find() method more readable, you can use its nice print function, like this
:
- db.monuments.find().pretty()
This time, the MongoDB shell will print the documents on several lines, each indented
: Output{ “_id” : ObjectId(“6105752352e6d1ebb7072647”), “name” : “The pyramids of Giza”, “city” : “Giza”, “country” : “Egypt”, “gps” : { “lat” : 29.97648, “lng” : 31.131302 } } { “_id” : ObjectId(“6105770952e6d1ebb7072648”), “name” : “The Valley of the Kings”, “city” : “Luxor”, “country” : “Egypt”, “gps” : { “lat” : 25.746424, “lng” : 32.605309 } } . . . .
Notice that in the previous two examples, the find() method was executed without any arguments. In both cases, he returned all objects in the collection. You can apply filters to a query to narrow down the results.
Remember from the previous examples that MongoDB automatically assigned The Valley of the Kings an object identifier with the value of ObjectId(“6105770952e6d1ebb7072648”). The object identifier is not just the hexadecimal string inside the ObjectId(“”), but the entire ObjectId object, a special data type used in MongoDB to store object identifiers.
The following find() method returns a single object accepting a query filter document as an argument. Query filter documents follow the same structure as documents that are inserted into a collection, consisting of fields and values, but are instead used to filter query results.
The query filter document used in this example includes the _id field, with the Valley of the Kings object ID as the value. To run this query against your own database, be sure to replace the highlighted object ID with that of one of the documents stored in your own monument collection
:
- db.monuments.find({“_id”: ObjectId(“6105770952e6d1ebb7072648”)}).pretty()
The query filter document in
this example uses the equal condition, which means that the query will return any document that has a field/value pair that matches the specified in the document. Basically, this example instructs the find() method to return only documents whose value _id equals ObjectId(“6105770952e6d1ebb7072648”).
After you run this method, MongoDB will return a single object that matches the requested object ID:
Output{ “_id” : ObjectId(“6105770952e6d1ebb7072648”), “name” : “The Valley of the Kings”, “city” : “Luxor”, “country” : “Egypt”, “gps” : { “lat” : 25.746424, “lng” : 32.605309 } } You
can also use the quality condition in any other field in the document. To illustrate, try searching for monuments in
France: db.monuments.find({“country”: “France”}).
- pretty()
This method will return two monuments
: Output{ “_id” : ObjectId(“6105770952e6d1ebb7072649”), “name” : “Arc de Triomphe”, “city” : “Paris”, “country” : “France”, “gps” : { “lat” : 48.48.873756, “lng” : 2.294946 } } { “_id” : ObjectId(“6105770952e6d1ebb707264a”), “name” : “The Eiffel Tower”, “city” : “Paris”, “country” : “France”, “gps” : { “lat” : 48.858093, “lng” : 2.294694 } } The documents of
Query filters are quite powerful and flexible, and allow you to apply complex filters to
collection documents.
You can learn more about the different ways to query collections in our tutorial How to create queries.
->
Step 4 — Updating
documents
It is common for documents within a document-oriented database like MongoDB to change over time. Sometimes your structures must evolve along with the changing requirements of an application, or the data itself may change. This step focuses on how to update existing documents by changing field values in individual documents, as well as adding a new field to each document in a collection.
Similar to the insertOne() and insertMany() methods, MongoDB provides methods that allow you to update a single document or multiple documents at once. An important difference with these update methods is that, when creating new documents, you only need to pass the document data as method arguments. To update an existing document in the collection, you must also pass an argument that specifies which document you want to update.
To enable users to do this, MongoDB uses the same query filter document mechanism in update methods that you used in the previous step to search and retrieve documents. Any query filter document that can be used to retrieve documents can also be used to specify documents to update.
Try renaming Arc de
Triomphe to Arc de Triomphe de l’Étoile. To do this, use
the updateOne() method that updates a single document: db.monuments.updateOne( { “name”: “Arc de Triomphe” }, { $set: { “name”: “
- Arc de
- Triomphe de l’Étoile”
- } )
- updateOne
}
The first argument of the
method is the query filter document with a single equal condition, as explained in the previous step.
In this example, { “name”: “Arc de Triomphe” } searches for documents with a name key that contains the value of Arc de Triomphe. Any valid query filter document can be used here.
The second argument is the upgrade document, which specifies which changes should be applied during the upgrade. The update document consists of update operators as keys and parameters for each of the operators as values. In this example, the update operator used is $set. It is responsible for setting document fields to new values and requires a JSON object with new field values. Here, set: { “name”: “Arc de Triomphe de l’Étoile” } tells MongoDB to set the value of the field name to Arc de Triomphe de l’Étoile.
The method will return a result that tells you that the query filter document found an object and that an object was successfully updated.
Output{ “acknowledged” : true, “matchedCount” : 1, “modifiedCount” : 1 }
To check if the update worked, try to retrieve all monuments related to
France:
- db.monuments.find({“country”: “France”}).pretty()
This time, the method returns Arc de Triomphe but with its full name, which was changed by the update operation:
Output{ “_id” : ObjectId(“6105770952e6d1ebb7072649”), “name” : “Arc de Triomphe de l’Étoile”, “city” : “Paris”, “country” : “France”, “gps” : { “lat” : 48.873756, “lng” : 2.294946 } } . . . .
To modify more than one document, you can use the updateMany() method.
As an example, suppose you notice that there is no information about who created the entry and you would like to credit the author who added each monument to the database. To do this, you’ll add a new editor field to each document in the monument collection.
The following example includes an empty query filter document. When you include an empty query document, this operation will match all documents in the collection, and the updateMany() method will affect each document. The update document adds a new editor field to each document and assigns it a Sammy value
:
- db.monuments.updateMany(
- )
- ” : 7
{ }, { $set: { “editor”: “Sammy
” } }
This method will return the following output: Output{ “acknowledged” : true, “matchedCount” : 7, “modifiedCount
} This output informs
you that seven documents were paired and seven were also modified.
Confirm that the changes were applied
:
- db.monuments.find().pretty()
Output{ “_id” : ObjectId(“6105752352e6d1ebb7072647”), “name” : “The pyramids of Giza”, “city” : “Giza”, “country” : “Egypt”, “gps” : { “lat” : 29..”name” : “The pyramids of Giza”, “city” : “Giza”, “country” : “Egypt”, “gps” : { “lat” : 29..”lat” : 29.97648, “lng” : 31.131302 }, “editor” : “Sammy” } { “_id” : ObjectId(“6105770952e6d1ebb7072648”), “name” : “The Valley of the Kings”, “city” : “Luxor”, “country” : “Egypt”, “gps” : { “lat” : 25.746424, “lng” : 32. 605309 }, “editor” : “Sammy” } . . .
All returned documents now have a new field called editor set to Sammy. When you provide a non-existent field name to the $set update operator, the update operation will create the missing fields in all matching documents and correctly set the new value.
Although you are likely to use $set more frequently, many other update operators are available in MongoDB, allowing you to make complex modifications to the data and structure of your documents. You can learn more about these update operators in the official MongoDB documentation on the subject.
Step 5 — Deleting Documents
There are times when database data becomes stale and needs to be deleted. As with Mongo’s update and insert operations, there is a deleteOne() method, which deletes only the first document that matches the query filter document, and deleteMany(), which deletes multiple objects at once.
To practice using these methods, start by trying to remove the monument from the Arc de Triomphe de l’Étoile that you modified earlier
:
- db.monuments.deleteOne( {
- Arc de Triomphe de l’Étoile” }
- )
“name”: “
Note that this method includes a query filter document like the previous update and recovery examples. As before, you can use any valid query to specify which documents will be deleted.
MongoDB will return the following output:
Output{ “acknowledged” : true, “deletedCount” : 1 } Here, the
result tells you how many documents were deleted
in the process.
Check if the document has been removed from the collection by consulting monuments in
France:
- db.monuments.find
({“country”: “France”}).pretty()
This time the method returns only one monument, The Eiffel Tower, since it removed the Arc de Triomphe de l’Étoile: Output{ “_id” : ObjectId(“6105770952e6d1ebb707264a”), “name” : “The Eiffel
Tower”, “city” : “Paris”, “country” : “France”, “gps” : { “lat” : 48.858093, “lng” : 2.294694 }, “editor” : “Sammy” }
To illustrate deleting multiple documents at once, delete all documents from the monument for which Sammy was the editor. This will
empty the collection, as you have previously designated Sammy as the editor of each monument: db.monuments.deleteMany( { “editor”: “Sammy” } )
This time, MongoDB lets you know that this method deleted six
documents: Output{ “acknowledged” : true, “deletedCount” : 6 }
You can verify that the monument collection is now empty by counting the number of documents it contains
- :
- db.monuments.count(
- )
Output0
Because you have just removed all documents from the collection, this command returns the expected result of 0
.
Conclusion By
reading this article, you became familiar with the concept of CRUD operations (Create, Read, Update and Delete), the four essential components of data management. You can now insert new documents into a MongoDB database, modify existing ones, retrieve documents already present in a collection, and also delete documents as needed.
However, keep in mind that this tutorial covered only one fundamental form of query filtering. MongoDB offers a robust query system that allows you to accurately select documents of interest based on complex criteria. For more information on how to create more complex queries, we recommend that you consult the official MongoDB documentation on the subject.