Share on

Introduction

When using MongoDB, you'll spend most of your time managing documents in some way or other. Whether you are creating new documents and adding them to collections, retrieving documents, updating data, or pruning stale items, documents are at the center of the MongoDB model.

In this guide, we'll cover what MongoDB documents are and then cover the common operations you will likely need to know about to manage a document-centered environment.

What are MongoDB documents?

In MongoDB, all data within databases and collections are stored in documents. Since collections do not specify a required schema by default, documents within a collection can contain an arbitrarily complex structure and need not match the format used by sibling documents. This provides incredible flexibility and allows schema to develop organically as application requirements change.

MongoDB documents themselves use the BSON data serialization format, a binary representation of the JSON JavaScript Object Notation. This provides an organized structure with defined data types that can be queried and operated upon programmatically.

BSON documents are represented by a pair of curly braces ({}) which contain key-value pairs. In BSON, these data couplets are known as the field and its value. The field comes first and is represented by a string. The value can be any valid BSON data type. A colon (:) separates the field from its value. A comma is used to separate each field and value pair from one another.

As an example, here is a valid BSON document that MongoDB can understand:

{
_id: 80380,
vehicle_type: "car",
mileage: 7377.80,
color: "blue",
markets: [
"US",
"UK"
],
options: {
transmission: "automatic",
num_doors: 4,
power_windows: true
}
}

Here, we can see quite a few types:

  • _id is an integer
  • vehicle_type and color are strings
  • mileage is a float
  • markets is an array of strings
  • options contains a nested document with values consisting of a string, an integer, and a boolean

Due to this flexibility, documents are a fairly flexible medium for storing data. New fields can be added easily, documents can be embedded within one another, and the structural complexity exactly matches the data being stored.

How to create new documents

To create a new document, change to a database where you want to store the created document. We'll use a school database for demonstration purposes in this article:

use school

You'll also want to choose the collection where you want to insert the documents. As with databases, you do not have to explicitly create the collection where you want to insert the document. MongoDB will automatically create it when the first data is written. For this example, we'll use a collection called students.

Now that you know where the document will be stored, you can insert a new document using one of the following methods.

Using the insert() method

The insert() method allows you to insert one or more documents into the collection it is called on.

To insert a single document, pass the document to the method by calling it on the collection. Here, we insert a new document for a student named Ashley:

db.students.insert(
{
first_name: "Ashley",
last_name: "Jenkins",
dob: new Date("January 08, 2003"),
grade_level: 8
}
)
WriteResult({ "nInserted" : 1 })

If you want to insert more than one document at the same time, instead of passing a document to insert(), pass an array of documents. We can add two new documents for students named Brian and Leah:

db.students.insert(
[
{
first_name: "Brian",
last_name: "McMantis",
dob: new Date("September 18, 2010"),
grade_level: 2
},
{
first_name: "Leah",
last_name: "Drake",
dob: new Date("October 03, 2009")
}
]
)
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})

Since we performed a bulk write operation, our return value is a BulkWriteResult instead of the WriteResult object we saw before.

While the insert() method is flexible, it has been deprecated in many MongoDB drivers in favor of the following two methods.

Using the insertOne() method

The insertOne() method can be used to insert a single document. Unlike the insert() method, it can only insert one document at a time, which makes its behavior a bit more predictable.

The syntax is the same as when you use insert() to add a single document. We can add another student named Naomi:

db.students.insertOne(
{
first_name: "Naomi",
last_name: "Pyani"
}
)
{
"acknowledged" : true,
"insertedId" : ObjectId("60e877914655cbf49ff7cb86")
}

Unlike with insert(), the insertOne() method returns a document containing some additional useful information. It confirms that the write was acknowledged by the cluster and it includes the object ID that was assigned to the document since we did not provide one.

Using the insertMany() method

To cover scenarios where you want to insert multiple documents at once, the insertMany() method is now recommended. Just as when inserting multiple documents with insert(), insertMany() takes an array of documents.

We can add three new students named Jasmine, Michael, and Toni:

db.students.insertMany(
[
{
first_name: "Jasmine",
last_name: "Took",
dob: new Date("April 11, 2011")
},
{
first_name: "Michael",
last_name: "Rodgers",
dob: new Date("February 25, 2008"),
grade_level: 6
},
{
first_name: "Toni",
last_name: "Fowler"
}
]
)
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60e8792d4655cbf49ff7cb87"),
ObjectId("60e8792d4655cbf49ff7cb88"),
ObjectId("60e8792d4655cbf49ff7cb89")
]
}

As with insertOne(), insertMany() returns a document which acknowledges the write and provides an array containing the IDs that have been assigned to the inserted documents.

How to query for existing documents

Querying documents is a fairly expansive topic that warrants its own article. You can find details about how to formulate queries to retrieve different types of documents in our guide on querying data within MongoDB.

While the details are best left in the article linked above, we can at least cover the methods that MongoDB provides to query documents. The main way to fetch documents from MongoDB is by calling the find() method on the collection in question.

For instance, to collect all of the documents from the students, you can call find() with no arguments:

db.students.find()
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }
{ "_id" : ObjectId("60e875d54655cbf49ff7cb85"), "first_name" : "Leah", "last_name" : "Drake", "dob" : ISODate("2009-10-03T00:00:00Z") }
{ "_id" : ObjectId("60e877914655cbf49ff7cb86"), "first_name" : "Naomi", "last_name" : "Pyani" }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb87"), "first_name" : "Jasmine", "last_name" : "Took", "dob" : ISODate("2011-04-11T00:00:00Z") }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }

To make the output more readable, you can also chain the pretty() method after find():

db.<collection>.find().pretty()
{
"_id" : ObjectId("60e8743b4655cbf49ff7cb83"),
"first_name" : "Ashley",
"last_name" : "Jenkins",
"dob" : ISODate("2003-01-08T00:00:00Z"),
"grade_level" : 8
}
{
"_id" : ObjectId("60e875d54655cbf49ff7cb84"),
"first_name" : "Brian",
"last_name" : "McMantis",
"dob" : ISODate("2010-09-18T00:00:00Z"),
"grade_level" : 2
}
{
"_id" : ObjectId("60e875d54655cbf49ff7cb85"),
"first_name" : "Leah",
"last_name" : "Drake",
"dob" : ISODate("2009-10-03T00:00:00Z")
}
{
"_id" : ObjectId("60e877914655cbf49ff7cb86"),
"first_name" : "Naomi",
"last_name" : "Pyani"
}
{
"_id" : ObjectId("60e8792d4655cbf49ff7cb87"),
"first_name" : "Jasmine",
"last_name" : "Took",
"dob" : ISODate("2011-04-11T00:00:00Z")
}
{
"_id" : ObjectId("60e8792d4655cbf49ff7cb88"),
"first_name" : "Michael",
"last_name" : "Rodgers",
"dob" : ISODate("2008-02-25T00:00:00Z"),
"grade_level" : 6
}
{
"_id" : ObjectId("60e8792d4655cbf49ff7cb89"),
"first_name" : "Toni",
"last_name" : "Fowler"
}

You can see that an _id field has been added to each of the documents. MongoDB requires a unique _id for each document in a collection. If you do not provide one upon object creation, it will add one for you. You can use this ID to retrieve a single object reliably:

db.students.find(
{
_id : ObjectId("60e8792d4655cbf49ff7cb89")
}
)
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler" }

You can find out more about various ways of querying data with the article linked above.

How to update existing documents

Many or most use cases for databases require you to be able to modify existing data within the database. A field might need to be updated to reflect a new value or you may need to append additional information to an existing document as it becomes available.

MongoDB uses a few related methods to update existing documents:

  • updateOne(): Updates a single document within a collection based on the provided filter.
  • updateMany(): Updates multiple documents within a collection that match the provided filter.
  • replaceOne(): Replaces an entire document in a collection based on the provided filter.

We will cover how to use each of these varieties to perform different types of updates.

Update operators

Before we take a look at each of the methods to update documents, we should go over some of the update operators that are available.

  • $currentDate: Sets a field's value to the current date, either as a date or timestamp type.
    • Syntax: { $currentDate: { <field>: <type>, ... } }
  • $inc: Increments a field's value by a set amount.
    • Syntax: { $inc: { <field>: <amount>, ... } }
  • $min: Updates a field's value if the specified value is less than the current value.
    • Syntax: { $min: { <field>: <value>, ... } }
  • $max: Updates a field's value if the specified value is more than the current value.
    • Syntax: { $max: { <field>: <value>, ... } }
  • $mul: Updates a field's value by multiplying it by the given number.
    • Syntax: { $mul: { <field>: <value>, ... } }
  • $rename: Renames a field name to a new identifier.
    • Syntax: { $rename: { <field>: <new_name>, ... } }
  • $set: Replaces the value of a field with the given value.
    • Syntax: { $set: { <field>: value, ... } }
  • $setOnInsert: During upsert operations, sets the value of a field if a new document is being created and does nothing otherwise.
    • Syntax: { $setOnInsert: { <field>: <value>, ... } }
  • $unset: Removes a field from the document.
    • Syntax: { $unset: { <field>: "", ... } }
  • $: A placeholder for the first array element that satisfies the query.
    • Syntax: { <update_operator>: {<array>.$: <value> } }
  • $[]: A placeholder for all array elements that satisfy the query.
    • Syntax: { <update_operator>: { <array>.$[]: <value> } }
  • $addToSet: Adds values to the array unless they're already present.
    • Syntax: { $addToSet: { <field>: <value>, ... } }
  • $pop: Removes the first or last element of an array.
    • Syntax: { $pop: { <field>: (-1 or 1), ... } }
  • $pull: Removes all elements of an array that match a condition.
    • Syntax: { $pull: { <field>: <condition>, ... } }
  • $push: Appends a value to an array.
    • Syntax: { $push: { <field>: <value>, ... } }
  • $pullAll: Removes all of the specified elements from an array.
    • Syntax: { $pullAll: { <field>: [ <value>, ... ], ...} }
  • $each: Modifies $addToSet and $push operators so that they add each element of an array instead of an array as a single element.
    • Syntax: { <update_operator>: { <field>: { $each: [ <value>, ... ] }, ... } }
  • $position: Used with $each and specifies the position the $push operator should insert at.
    • Syntax: { $push: { <field>: { $each: [ <value>, ... ], $position: <num> } } }
  • $slice: Used with $each and $push to limit the number of total elements in the array.
    • Syntax: { $push: { <field>: { $each: [ <value>, ... ], $slice: <num> } } }
  • $sort: Used with $each and $push to sort array elements.
    • Syntax: { $push: { <field>: { $each: [ <value>, ... ], $sort: <sort_order> } } }

These various update operators allow you to update various fields of your documents in different ways.

Updating a single document in a collection

MongoDB's updateOne() method is used to update a single document within a collection. The method takes two required arguments as well as a document specifying optional arguments.

The first argument is a document that specifies the filter conditions that will be used to select documents. Since the updateOne() method modifies at most one document in a collection, the first document that satisfies the filter conditions will be used.

The second argument specifies the update operation that should be executed. The update operations given above can be specified here to alter the contents of the matched document.

The third argument is a document of various options to modify the behavior of the method. The most important potential values are:

  • upsert: Turns the operation into an upsert procedure by inserting a new document if the filter does not match any existent documents.
  • collation: A document that defines language-specific rules that should apply for the operation.

As an example, we can update a single student record that we filter by the _id field to ensure that we target the correct document. We can set the grade_level to a new value:

db.students.updateOne(
{ _id: ObjectId("60e8792d4655cbf49ff7cb89") },
{ $set: { grade_level: 3 } }
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

Updating multiple documents in a collection

MongoDB's updateMany() method works similar to the updateOne() method, but instead updates any document that matches the given filter instead of stopping after the first match.

The updateMany() syntax exactly follows the updateOne() syntax, so the only difference is the scope of the operation.

As an example, if we want to change all of the instances of "composition" to "writing" in the subjects array in our teachers collection documents, we could use something like this:

db.teachers.updateMany(
{ subject: "composition" },
{ $set: { "subjects.$": "writing" } }
)
{ "acknowledged" : true, "matchedCount" : 3, "modifiedCount" : 3 }

If you check the documents, each instance of "composition" should have been replaced with "writing":

db.teachers.find()
{ "_id" : ObjectId("60eddca65eb74f5c676f3baa"), "first_name" : "Nancy", "last_name" : "Smith", "subjects" : [ "vocabulary", "pronunciation" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bab"), "first_name" : "Ronald", "last_name" : "Taft", "subjects" : [ "literature", "grammar", "writing" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bac"), "first_name" : "Casey", "last_name" : "Meyers", "subjects" : [ "literature", "writing", "grammar" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bad"), "first_name" : "Rebecca", "last_name" : "Carrie", "subjects" : [ "grammar", "literature" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bae"), "first_name" : "Sophie", "last_name" : "Daggs", "subjects" : [ "literature", "writing", "grammar", "vocabulary", "pronunciation" ] }

Replacing a document

The replaceOne() method works similar to the updateOne() method, but replaces the entire document instead of updating individual fields. The syntax is the same as the previous two commands.

For instance, if Nancy Smith leaves your school and you replace her with a teacher named Clara Newman who teaches literature, you could type the following:

db.teachers.replaceOne(
{
$and: [
{ first_name: "Nancy" },
{ last_name: "Smith" }
]
},
{
first_name: "Clara",
last_name: "Newman",
subjects: [ "literature" ]
}
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

You can see that the matched document has been removed and that the specified document has replaced it:

db.teachers.find()
{ "_id" : ObjectId("60eddca65eb74f5c676f3baa"), "first_name" : "Clara", "last_name" : "Newman", "subjects" : [ "literature" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bab"), "first_name" : "Ronald", "last_name" : "Taft", "subjects" : [ "literature", "grammar", "writing" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bac"), "first_name" : "Casey", "last_name" : "Meyers", "subjects" : [ "literature", "writing", "grammar" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bad"), "first_name" : "Rebecca", "last_name" : "Carrie", "subjects" : [ "grammar", "literature" ] }
{ "_id" : ObjectId("60eddca65eb74f5c676f3bae"), "first_name" : "Sophie", "last_name" : "Daggs", "subjects" : [ "literature", "writing", "grammar", "vocabulary", "pronunciation" ] }

How to delete documents

Removing documents from collections is also part of the document life cycle. To remove a document, you can use the deleteOne() or deleteMany() methods. They have the same syntax, and differ only in how many documents they operate on.

For the most part, all you have to do to delete documents with either of these methods is to provide it with a filter document that specifies how you wish to select the document to be deleted. The deleteOne() method will delete at most one document (regardless of how many matches the filter produces) while the deleteMany() method deletes every document that matches the filter conditions.

For example, to delete a single student, you can provide an _id to match them explicitly:

db.students.deleteOne({
_id: ObjectId("60e8792d4655cbf49ff7cb87")
})
{ "acknowledged" : true, "deletedCount" : 1 }

If we want to delete any student that does not have a grade level assigned, we can use the deleteMany() method instead:

db.students.deleteMany({
grade_level: { $eq: null }
})
{ "acknowledged" : true, "deletedCount" : 2 }

If we check, we should see that all of the remaining students have a grade level assigned:

db.students.find()
{ "_id" : ObjectId("60e8743b4655cbf49ff7cb83"), "first_name" : "Ashley", "last_name" : "Jenkins", "dob" : ISODate("2003-01-08T00:00:00Z"), "grade_level" : 8 }
{ "_id" : ObjectId("60e875d54655cbf49ff7cb84"), "first_name" : "Brian", "last_name" : "McMantis", "dob" : ISODate("2010-09-18T00:00:00Z"), "grade_level" : 2 }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb88"), "first_name" : "Michael", "last_name" : "Rodgers", "dob" : ISODate("2008-02-25T00:00:00Z"), "grade_level" : 6 }
{ "_id" : ObjectId("60e8792d4655cbf49ff7cb89"), "first_name" : "Toni", "last_name" : "Fowler", "grade_level" : 3 }

Conclusion

Learning how to create, query for, update, and remove documents gives you the skills you need to effectively manage documents within MongoDB on a daily basis. Becoming familiar with the various document and collection methods and the operators that allow you to match and modify information lets you express complex thoughts that the database system can understand.

FAQ

An embedded, or nested, document in MongoDB is a document which contains another document inside of it.

The following is an example of an embedded document where address —denoted as a subdocument by additional curly brackets— can be accessed with the user record.

db.user.findOne({_id: 111111})
{
_id: 111111,
email: “email@example.com”,
name: {given: “Jane”, family: “Han”},
address: {
street: “111 Elm Street”,
city: “Springfield”,
state: “Ohio”,
country: “US”,
zip: “00000”,
}
}

The maximum document size in MongoDB is 16 megabytes.

This limitation helps ensure that a single document cannot use an execessive amount of RAM or, during transmission, excessive amount of bandwidth.

To store documents larger than 16mb, MongoDB provides the GridFS API.

To remove documents, you can either use the deleteOne() or deleteMany() methods. They have the same syntax, and differ only in how many documents they operate on.

To delete a single document, the basic syntax looks as follows for removing a document with a specific _id:

db.students.deleteOne({
_id: ObjectId("60e8792d4655cbf49ff7cb87")
})

And to delete many documents matching a certain criteria, the syntax looks similarly:

db.students.deleteMany({
grade_level: { $eq: null }
})

To modify documents in MongoDB, there are a few related update methods.

Specifically, for appending new data to a document, you can use the $addToSet update operator. This operator adds values to the array of the document unless they're already present.

There is not a specific method to explicitly compare one document to another in MongoDB. It can be done by configuring a query comparing equality between any of the documents' fields with operators.

Comparison can also be done by configuring an aggregation pipeline. This method allows you to create stages that:

  • group values from multiple documents together
  • perform operations on the grouped data to return a single result
  • analyze data changes over time
About the Author(s)
Justin Ellingwood

Justin Ellingwood

Justin has been writing about databases, Linux, infrastructure, and developer tools since 2013. He currently lives in Berlin with his wife and two rabbits. He doesn't usually have to write in the third person, which is a relief for all parties involved.