How to Use Indexes in MongoDB

How to Use Indexes in MongoDB
Bhuban Mishra
Technical writer
MongoDB
24.12.2024
Reading time: 8 min

A MongoDB index is a special data structure comprising the search field and its location in the MongoDB document. Indexing allows MongoDB to ind and retrieve data, reducing query execution time quickly.

Imagine searching for a spelling in a dictionary. Instead of flipping through each page, you scroll to the alphabet section where the name begins, greatly narrowing your search.

MongoDB indexing is essential for fast document retrieval, sorting, and filtering. Without it, databases become slow, especially with large collections, and response times increase.

MongoDB indexing strategies play a crucial role in reducing the application response times. 

How do MongoDB Indexes Work?

MongoDB uses a B-tree index, organizing entries in sorted order for efficient insertion, deletion, and search. Creating an index adds a structure with document keys and links to the corresponding documents.

Key Terminologies for MongoDB Indexing

  • Index Key: It is simply the field or fields in a MongoDB document.

  • Index Direction: The index direction commonly referred to as index order, determines if the field is sorted in ascending(1) and descending(-1) order.                

Prerequisites

To proceed with this tutorial, you will need to:

  • Have a MongoDB database installation or get your free MongoDB atlas account from here.

  • This tutorial assumes you have some familiarity with mongosh. You should know how to switch to different databases and query collections.

  • Download the test database:

wget https://raw.githubusercontent.com/ozlerhakan/mongodb-json-files/refs/heads/master/datasets/companies.json

Some parts of the tutorial use the Airbnb review database.

  • Import it. If you have local installation of MongoDB, you can import this JSON database with mongoimport utility. 

mongoimport --collection="companies" --file='companies.json' --db hostman-tutorial
mongoimport --collection="reviews" --file='reviews.csv' –type csv --db hostman-tutorial --headerline

Image2

How to manage MongoDB Indexes

To show indexes in MongoDB:

db.reviews.getIndexes()

To create an index in MongoDB, simply use the function db.createIndex and pass the field name.

db.reviews.createIndex({ reviewer_name: 1 })

To drop the index in MongoDB:

db.reviews.dropIndex("reviewer_name_1")

Image4

MongoDB Indexing Strategies

It obviously depends upon the scenario if creating an index on a single field or a combination of fields will be more efficient. It’s also interesting to note what kind of information the field is storing. 

Here is a list of different techniques.

Single Field Index

Single field index is useful in scenarios where MongoDB needs to frequently query data by a particular field.

Obviously, a single field index is not a viable option in case you need to support searching across multiple fields.

In the reviews dataset, it might be interesting to list only the property reviewed by a particular person.

db.reviews.createIndex({ reviewer_name : 1 })

To verify if index creation has benefitted the database queries:

db.reviews.find({ reviewer_name: “Kristen” }).explain(“executionStats”)

Image3

The executionTimeMillis has been drastically reduced from 31 ms to 1 ms. Similarly, totalDocsExamined was reduced from 24752 to 47 only, thanks to MongoDB indexing.

To retrieve comments of multiple reviewers, use the MongoDB $in operator.

db.reviews.find(
      { reviewer_name : { $in: ["Christopher", "Altay", "Kristen"] } }, 
      { reviewer_name:1, comments: 1 }
)

Compound Index

What if a database frequently needs to query by three different fields, that’s where compound index comes to the rescue.

db.companies.createIndex({
  category_code: 1,
  number_of_employees: 1,
  founded_year: 1
})

Now, let's verify how the compound index improves our query using explain('executionStats').

db.companies.find({ category_code: "enterprise", number_of_employees: { $gte: 500, $lte: 1000 }, founded_year: { $gte: 1990 } }).explain("executionStats")

Image6

Remember, if you have hundreds of compound indexes, it can cause a significant downfall in the write performance of the database. The reason is its high resource usage.

Multikey Index

What if the MongoDB field that needs to be indexed is an array? For example, a quick database inspection with the following command reveals relationships is an array field.

db.companies.find().limit(1)

Image5

The multikey index really shines here. It would be really interesting to filter out those persons who have still held their positions. For this purpose, you can create a multikey index on the is_past field.

db.companies.createIndex({ "relationships.is_past": 1 })

Image1

Text Index

For full-text search in MongoDB, use a text index, like in the Airbnb review database sample. 

db.reviews.createIndex({ comments:“text” })

[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  {
	v: 2,
	key: { _fts: 'text', _ftsx: 1 },
	name: 'comments_text',
	weights: { comments: 1 },
	default_language: 'english',
	language_override: 'language',
	textIndexVersion: 3
  }
]

Now, let’s search for a large-bedroom apartment.

db.reviews.find({ $text: { $search: "large bedroom" } }).limit(20)

If you ever need to implement sorting, MongoDB does provide the sort function and textScore metadata for searching.

db.reviews.find({ $text: { $search: "large bedroom" } })
  .sort({ score: { $meta: "textScore" } })

While creating a text index in MongoDB, if the key is an array, it would index and search across each element of the array.

Hash Index

MongoDB internally uses the hash function and uses it as a reference to the contents of fields in consideration.

If you’re using the MongoDB sharding feature, a hash index can make it more performant. 

db.users.createIndex({ password: "hashed" })
db.users.find({ password: “very-long-hash” })

While the hash index is great, there are a few limitations though. For instance, you can’t use range queries like $gte, $lte, $gt.

Sparse Index

Whenever you come across a lot of null, missing, or boolean values in a MongoDB collection, a sparse index is worth consideration. Sparse indexes are easier to maintain, and can significantly improve query performance.

Let’s create an index for the documents that have a phone number field.

db.customers.createIndex({ phone: 1 }, { sparse: true })

Consider, out of 1 million customers only 20% of them provided their phone number. So, while creating a sparse index, it will only create an index for 0.2 million records. Isn’t this great?

Mongoose Indexing

Mongoose is similar to what SQLalchemy is for Flask. It makes working with MongoDB databases a lot easier in Node.js applications. 

Here are two different approaches.

  1. Index with Mongoose Schema: Mongoose schema determines the structure of a collection.

Mongoose provides an index method to create a new index on the desired schema. Every mongoose schema is tied to a model.

const mongoose = require(‘mongoose’);
const reviewSchema = new mongoose.Schema({
  property: String,
  comment: String
});

reviewSchema.index({ comment: 'text' });

const Review = mongoose.model(‘Review’, reviewSchema);
  1. Index with MongoDB Collection: The second strategy is to retrieve the collection, the Mongoose way, and then set up an index.

const mongoose = require(‘mongoose’);

mongoose.connect('mongodb://localhost:27017/hostman-mongodb-tutorial, { useNewUrlParser: true, useUnifiedTopology: true });

mongoose.connection.once('open', function() {
	const reviewsCollection = mongoose.connection.collection(‘reviews’);

      reviewsCollection.createIndex({ email: 1 }, (err, result) => {
    	if (err) {
        	console.error('Error creating index:', err);
    	} else {
        	console.log('Index created successfully:', result);
    	}
	});
});

Exploring MongoDB's Internal Index Intersection for Complex Queries

Index intersection is a technique to combine multiple indexes to satisfy a complex query. The benefit is you get improved read performance without sacrificing index size in the long run.

Consider the scenario:

db.reviews.createIndex({ listing_id : 1 })
db.reviews.createIndex({ reviewer_id : 1 })

Perform the following query:

db.reviews.find({ listing_id: 2992450, reviewer_id: 16827297 })

With these two indexes, the query will use index intersection, but only if MongoDB’s query optimizer finds it more efficient.

MongoDB Indexing tradeoffs

No doubt, Indexing improves application response time but don’t overdo it. Too many indexes can be hard to maintain as data grows. Here are a few pointers:

  • Write Performance: Indexing requires additional disk I/O and CPU resources. For every insert, update, and delete, MongoDB needs to perform an additional operation. Think carefully!
  • Data Consistency: Index maintenance is another critical tradeoff in MongoDB indexing. Indexes must be regularly maintained to ensure data consistency and prevent corruption.
  • Index Size: Larger indexes can provide faster query performance but require more disk space.

Conclusion

MongoDB indexes are a great way to improve query times for document retrieval, and they’re crucial for high-availability setups. However, understanding how indexing works, its tradeoffs and the challenges it can bring for a maintenance team can help you get the most out of it.

At Hostman, you can deploy a MongoDB cloud database in a few seconds and start working in no time.

MongoDB
24.12.2024
Reading time: 8 min

Similar

MongoDB

How To Use the MongoDB Shell

MongoDB Shell is an adaptive JavaScript and Node.js REPL (Read-Eval-Print Loop) environment for dealing with MongoDB deployments. It is an important utility for querying data, administering databases, and running various operations. It provides an attractive view for controlling databases, whether you're using them on a remote server or MongoDB locally. This article will demonstrate the step-by-step guidelines for utilizing the MongoDB shell. Step 1: Installation of MongoDB Shell Before starting operations, confirm that users have installed it on the system. If not, first, download the appropriate version via the official site and consider the installation instructions for the system. Windows Visit the official page, pick the Windows version, and start downloading. macOS On the official page, choose the macOS version and begin the downloading process. Alternatively, use Homebrew by executing the commands: brew tap mongodb/brew brew install mongosh Linux Consider the guidelines provided on the website for the Linux OS. For example, on a Debian-based operating system, follow these steps: Add the GPG key for the MongoDB repository: curl -fsSL https://pgp.mongodb.com/server-7.0.asc |  sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor Add the MongoDB repository to your system: echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list Update the package list: sudo apt update Install MongoDB: sudo apt install mongodb-org -y Upon the successful installation, authenticate the installed version: mongod --version Once the installation is done, enable, start, and check the services of it: sudo systemctl enable mongod sudo systemctl start mongod sudo systemctl status mongod Step 2: Establish a Connection to an Instance Once the installation is done, you can establish connections to its instance. If it is local, enter mongosh. It establishes the connection to the instance by default. It is running at port 27017 on localhost: mongosh The following syntax is utilized to establish a connection to the remote server: mongodb+srv://<username>:<password>@<cluster-url>/<db>?retryWrites=true&w=majority Modify <username>, <password>, <cluster-url>, and <db> with original credentials and connection details. Step 3: Navigation to the Terminal Once connected, you can work with their DBs. Before it, the interface greets a message: The assigned DB on a freshly launched shell instance is called a test. It is safe to use for experimenting. Useful operations are given below: Exploring all Databases First, run show dbs, which gives a view of every database that is available: show dbs Accessing the Current Database The majority of commands operate on a database or a collection that is contained within the database. In order to accomplish this, the object db represents the presently selected database and is available: db Switching to the Database Enter the use command with the DB name, e.g., new_db, to create or switch to the specified one: use new_db Replace new_db with the actual name of the DB. Insertion of an Object First, enter a name as an object into the student_data in the existing new_db: db.student_data.insertOne({name: 'School has 500 students'}) Users can also insert multiple documents into the student_data, each containing a name field with specified values. This allows for batch insertion of data into the collection: db.student_data.insertMany([ {name: 'School has 500 students'}, {name: 'School has 600 students'} ]) Viewing Collections Once the input is inserted, display the existing collections: show collections If you have not done any task, leave the interface by executing: exit You have to understand the basic shell operations. Step 4: Operations Using CRUD When working with the shell, CRUD (Create, Read, Update, Delete) operations are essential. Let’s perform some basic ones: Creating/Inserting Data When inserting new information into the collection, employ the insertOne function. Let us create a new one and fill it with the required information, including name, age, and city:  db.collection.insertOne({ name: "Harry", age: 45, city: "Sydney" }) Finding/Reading Data You can query documents that are associated with the collection by employing the find function. For instance, all entries with an age greater than 25 are retrieved: db.collection.find({ age: { $gt: 25 } }) //  Condition where age is greater than 25 Modifying Data Use the updateOne or updateMany functions to make changes to documents that exist. For instance, the age with Harry's name is updated to 50 on the existing one: db.collection.updateOne({ name: "Harry" }, { $set: { age: 50 } }) Deleting Data Use the deleteOne or deleteMany methods to eliminate entries from the collection that are available. This command removes one document from the available ones with the value John in the name field: db.collection.deleteOne({ name: "John" }) Step 5: Advanced Usage In this step, carry out complex operations via the advanced functionalities. By offering debugging, profiling, and performance optimization tools, the shell helps you find bottlenecks and optimize your setup. Aggregation Pipeline With the help of pipelines, readers can compute records and get calculated results. By using pipelines, create complex analytics and transformations that will assist you in extracting insightful information from your raw. For executing a pipeline of stages, utilize the aggregate function. Here’s a basic code example: db.collection.aggregate([ { $match: { status: "A" } }, { $group: { _id: "$city", total: { $sum: "$amount" } } }, { $sort: { total: -1 } } ]) In the script, the pipeline filters documents with status A, groups them by city, sums the amounts, and sorts the results in descending order. One strong tool for data analysis and transformation is the aggregation pipeline. It is composed of several stages, each of which changes the stream of documents. These stages include: $project: Selects or excludes specific fields. $match: Applying a query condition to filter them. $group: Merges input by a field and calculates aggregations. $sort: Arrange entries according to a given field. $limit: Restricts the amount of records. $skip: Skips a specified number of records. MapReduce An effective paradigm for computing huge datasets. For executing MapReduce jobs, utilize the mapReduce command: // Sample collection data db.collection.insertMany([ { name: "Harry", age: 25, salary: 5000 }, { name: "Buttler", age: 30, salary: 6000 }, { name: "Morgan", age: 35, salary: 7000 } ]); // Map function var mapFunction = function() { emit(this.age, this.salary); }; // Reduce function var reduceFunction = function(keyAge, valuesSalaries) { return Array.sum(valuesSalaries); }; // Run MapReduce db.runCommand({ mapreduce: "collection", map: mapFunction, reduce: reduceFunction, out: "results" }); db.results.find().forEach(printjson); // Output the results In this example, the mapFunction emits the age as the key and the salary as the value.  The reduceFunction sums the salaries for each age group.  The results are stored in a new collection called results, and the final output is printed using db.results.find().forEach(printjson). The output is given below: Projection Utilize the projection operator to specify which fields should be included or excluded from the result set. It retrieves all info associated with the particular query, e.g., displaying only the name and age fields. This offers anyone the ability to visualize specific results while excluding others. Let’s project only name and age fields: db.collection.find({}, { name: 1, age: 1 })  Sorting Sort the results employing the sort function. It retrieves every document belonging to the set. Then, sort them in descending sequence based on the age. It gives a view with the highest age values first. Let’s sort by age in descending order: db.collection.find().sort({ age: -1 })  Limiting Users limit the entries of results via the limit function. For instance, obtain the initial three documents linked to the collection. It is useful for previewing a small subset of information without fetching the entire list. Let’s limit to 3 results: db.collection.find().limit(3)  Skipping Skip an entry is done via the skip function. For instance, skipping the initial two documents that linked to the collection. It is beneficial for paginating results or ignoring an entry of initial documents. Let’s skip the first 2 results: db.collection.find().skip(2)  Step 6: Scripting with Shell Scripts for task automation can be written by users within the shell. To achieve it, save the script in the .js file and run the mongosh. It is beneficial for executing repetitive tasks efficiently, e.g., data seeding or batch updates: mongosh script.js By mastering the MongoDB command, you gain valuable insights into data. Conclusion With the help of the immersive MongoDB shell interface, you conduct repetitive management tasks like writing, reading, and manipulating. In addition, query existing collections, add new objects to the DB, and carry out management administrative tasks. From simple CRUD tasks to complex aggregations and scripting, users can efficiently utilize the interface to carry out a variety of activities.  By executing scripts, readers efficiently perform repetitive tasks. This tutorial has covered the installation, configuration, and managerial tasks for managing the DBs, their collections, and their users.  At Hostman, you can deploy a MongoDB cloud database in a few seconds and start working in no time.
19 December 2024 · 8 min to read
MongoDB

How to Work with MongoDB Queries

MongoDB is not a traditional relational database management system. This is reflected in many aspects: the principles of database design, the format of stored data, the approach to scaling, and the query language. The primary language for creating queries in relational databases is SQL. However, MongoDB uses its own syntax for queries. In this guide, we’ll discuss how to create queries and which commands are used. Structure of MongoDB A MongoDB database consists of collections similar to tables in relational databases. Each collection has its own unique name. Unlike table-based databases, collections do not have a strict data structure with a fixed number of columns and data types. Collections store documents, which are objects that resemble JSON format. An example of an employee document might look like this: { "name": "Mary", "surname": "Jameson", "age": 27, "salary": "100000", "department": "marketing", "date of birth": "15.02.1997" } Data in documents can be represented in various data types. In this example, all the data is described as strings. Database and Collection-Level Queries We will be writing and composing queries in MongoDB Compass. For more details on installing MongoDB on Ubuntu, refer to our tutorial. After installation, three databases will be available on the local server: To display them, we use the show databases command: show databases# Output: admin 40.00 KiB config 60.00 KiB local 40.00 KiB A shorter version, show dbs, can also be used: show dbs# Output: admin 40.00 KiB config 60.00 KiB local 40.00 KiB To work with a specific database, use the use command: use testdb Output: 'switched to db testdb' The testdb database does not exist on our server. If the terminal cannot find the specified database when executing the use command, it will create a new one with that name. Use the db.createCollection("collection_name") command to create collections. Let’s create a collection in the testdb database: db.createCollection('cloud'){ ok: 1 } To list collections: show collectionscloud To delete a collection, use the drop() command: db.cloud.drop()true List collections again to confirm deletion: show collections To delete the entire database while working with it, use the db.dropDatabase() command: db.dropDatabase() Output: { ok: 1, dropped: 'testdb' } Adding and Deleting Documents Let’s restore the database and create a collection in it: use testdb# Output:'switched to db testdb' db.createCollection('employees')# Output:{ ok: 1 } Then, we’ll add the first document: db.employees.insert({ name: "Mary", surname: "Jameson", age: 27, salary: 100000, department: "marketing", date_of_birth: "15.02.1997" }) Output: 'DeprecationWarning: Collection.insert() is deprecated. Use insertOne, insertMany, or bulkWrite.'{ acknowledged: true,  insertedIds: { '0': ObjectId("637c9cbd7025c2523a76fe64") } } After executing insert, the terminal suggests using the insertOne, insertMany, or bulkWrite methods to optimize queries, as insert is now deprecated. insertOne - Adding a Single Document The insertOne method adds one document to the collection: db.employees.insertOne({ name: "James", surname: "Johns", age: 37, salary: 150000, department: "QA", date_of_birth: "12.06.1987" }) Output: { acknowledged: true,  insertedId: ObjectId("637ca6127025c2523a76fe65") } insertMany - Adding Multiple Documents The insertMany method adds an array of documents to the collection: db.employees.insertMany( [{ name: "Andrew", surname: "Stuart", age: 21, salary: 12000, department: "Tech Support", date_of_birth: "15.10.2003" }, { name: "Natalie", surname: "Richardson", age: 45, salary: 200000, department: "HR", date_of_birth: "6.05.1979" }] ) Output: { acknowledged: true, insertedIds: { '0': ObjectId("637ca7817025c2523a76fe66"), '1': ObjectId("637ca7817025c2523a76fe67") } } bulkWrite - Performing Multiple Operations The bulkWrite method allows you to perform multiple operations, including inserting, deleting, and updating documents: db.employees.bulkWrite([{ insertOne: { document: { name: "Michael", surname: "Smith", age: 32, salary: 20000, department: "Tech Support", date_of_birth: "10.01.1992" } } }]) Output: { acknowledged: true, insertedCount: 1, insertedIds: { '0': ObjectId("637cafaa7025c2523a76fe68") }, matchedCount: 0, modifiedCount: 0, deletedCount: 0, upsertedCount: 0, upsertedIds: {} } Using these methods—insertOne, insertMany, and bulkWrite—can improve efficiency and provide more control over document management in MongoDB. Document Search The find() query is MongoDB's equivalent of SQL's SELECT. This query searches and displays documents in a collection. To start, let’s output all documents in the employees collection: db.employees.find() Output: [ { "_id": ObjectId("637c9cbd7025c2523a76fe64"), "name": "Mary", "surname": "Jameson", "age": 27, "salary": 100000, "department": "marketing", "date_of_birth": "15.02.1997" }, { "_id": ObjectId("637ca6127025c2523a76fe65"), "name": "James", "surname": "Johns", "age": 37, "salary": 150000, "department": "QA", "date_of_birth": "12.06.1987" }, { "_id": ObjectId("637ca7817025c2523a76fe66"), "name": "Andrew", "surname": "Stuart", "age": 21, "salary": 12000, "department": "Tech Support", "date_of_birth": "15.10.2003" }, { "_id": ObjectId("637ca7817025c2523a76fe67"), "name": "Natalie", "surname": "Richardson", "age": 45, "salary": 200000, "department": "HR", "date_of_birth": "6.05.1979" } ] Search by Criteria To find a document with specific parameters, pass them as arguments to the find() query. For example, let’s find an employee with a salary of 50000: db.employees.find({ salary: 50000 }) Output: [] In this case, no employees have a salary of 50000, so the output is empty. If there are multiple parameters, list them separated by commas: db.employees.find({ salary: 12000, name: "Andrew" }) Output: [ { "_id": ObjectId("637ca7817025c2523a76fe66"), "name": "Andrew", "surname": "Stuart", "age": 21, "salary": 12000, "department": "Tech Support", "date_of_birth": "15.10.2003" } ] Find with OR Condition To set an OR condition in the MongoDB query, use $or: db.employees.find({ $or: [{ salary: 50000 }, { name: "Natalie" }] }) Output: [ { "_id": ObjectId("637ca7817025c2523a76fe67"), "name": "Natalie", "surname": "Richardson", "age": 45, "salary": 200000, "department": "HR", "date_of_birth": "6.05.1979" } ] Search with Comparison The following comparison operators are used: $lt — less than $lte — less than or equal to $gt — greater than $gte — greater than or equal to $ne — not equal For example, let’s find employees with a salary greater than 100000 and under the age of 30: db.employees.find({ salary: { $gte: 100000 }, age: { $lt: 30 } }) Output: [ { "_id": ObjectId("637c9cbd7025c2523a76fe64"), "name": "Mary", "surname": "Jameson", "age": 27, "salary": 100000, "department": "marketing", "date_of_birth": "15.02.1997" } ] Sorting The sort() method sorts documents based on a given parameter and takes a number: 1 for ascending order or -1 for descending order. Let’s sort employees by age: db.employees.find().sort({ age: 1 }) Output: [ { "_id": ObjectId("637ca7817025c2523a76fe66"), "name": "Andrew", "surname": "Stuart", "age": 21, "salary": 12000, "department": "Tech Support", "date_of_birth": "15.10.2003" }, { "_id": ObjectId("637c9cbd7025c2523a76fe64"), "name": "Mary", "surname": "Jameson", "age": 27, "salary": 100000, "department": "marketing", "date_of_birth": "15.02.1997" }, { "_id": ObjectId("637ca6127025c2523a76fe65"), "name": "James", "surname": "Johns", "age": 37, "salary": 150000, "department": "QA", "date_of_birth": "12.06.1987" }, { "_id": ObjectId("637ca7817025c2523a76fe67"), "name": "Natalie", "surname": "Richardson", "age": 45, "salary": 200000, "department": "HR", "date_of_birth": "6.05.1979" } ] Limiting Results To limit the number of documents returned, use the limit() method: db.employees.find().sort({ age: 1 }).limit(2) Output: [ { "_id": ObjectId("637ca7817025c2523a76fe66"), "name": "Andrew", "surname": "Stuart", "age": 21, "salary": 12000, "department": "Tech Support", "date_of_birth": "15.10.2003" }, { "_id": ObjectId("637c9cbd7025c2523a76fe64"), "name": "Mary", "surname": "Jameson", "age": 27, "salary": 100000, "department": "marketing", "date_of_birth": "15.02.1997" } ] Document Updates To update documents in a MongoDB database, use a query with the update() command. It takes two parameters: the first specifies which documents to update, and the second indicates which fields to change and their new values. Here’s an example: db.employees.update({ name: 'Mary' }, { $set: { name: 'Anna', age: 51, date_of_birth: '15.11.1972' } }) Then, to verify the update, we can search for documents with the new name: db.employees.find({ name: 'Anna' }) Output: [ { "_id": ObjectId("637c9cbd7025c2523a76fe64"), "name": "Anna", "surname": "Jameson", "age": 51, "salary": 100000, "department": "marketing", "date_of_birth": "15.11.1972" } ] Renaming Fields To rename fields, use the $rename operator. In this case, let’s rename name to first_name: db.employees.updateMany({}, { $rename: { name: 'first_name' } }) Now, all documents with the name field will have it replaced by first_name. Document Deletion MongoDB provides two functions for deleting documents: deleteOne() and deleteMany(). deleteOne() The deleteOne() function deletes the first document that matches the criteria. For example, let’s delete an employee named "Natalie": db.employees.deleteOne({ first_name: 'Natalie' }) Output: { acknowledged: true, deletedCount: 1 } deleteMany() The deleteMany() function deletes all documents that match the criteria. Let’s delete all employees in the Tech Support department: db.employees.deleteMany({ department: 'Tech Support' }) Output: { acknowledged: true, deletedCount: 2 } After these deletions, only two documents should remain in the employees collection. Let’s check: db.employees.find() Final Output: [ { "_id": ObjectId("637c9cbd7025c2523a76fe64"), "first_name": "Anna", "surname": "Jameson", "age": 51, "salary": 100000, "department": "marketing", "date_of_birth": "15.11.1972" }, { "_id": ObjectId("637ca6127025c2523a76fe65"), "first_name": "James", "surname": "Johns", "age": 37, "salary": 150000, "department": "QA", "date_of_birth": "12.06.1987" } ] In summary, these operations—update, $rename, deleteOne, and deleteMany—allow you to manage document updates and deletions efficiently in MongoDB. MongoDB Query Optimization To improve the speed of your queries, consider the following tips: Create indexes for frequently used queries. Limit the number of returned documents. MongoDB retrieves all matching documents by default, so use the limit() method if you only need part of the result. Return only necessary fields from documents. You can enhance query performance by specifying only the required fields in the search result. Use more "selective" queries. For example, checking by _id will return no more than one document. Aim to use parameters in MongoDB queries that most accurately describe the documents you need. Conclusion MongoDB provides a straightforward query syntax that enables efficient document management within databases. In this material, we covered basic MongoDB queries that encompass primary document management tasks. We used a database hosted locally, but you can also host a database in the cloud using Hostman Managed Databases. Cloud databases are easier to administer and scale and can be managed and created using a web interface.
02 November 2024 · 10 min to read
Node.js

How to Connect a Node.js App to MongoDB

When developing Node.js applications, you might need to store data somewhere. Using application variables or files on the host machine as data storage is not always convenient. A better option to consider is connecting to an external database application. MongoDB is great for integration with Node.js. In MongoDB, data is presented in JSON format, which works well with JavaScript.  In this article, we'll show you how to connect a MongoDB database to your Node.js application and look at several common database queries. This guide works for Node.js version 14 and higher and MongoDB version 4.4 and higher. Test database As a test database, we will use the testdb database, which contains the employees collection. It stores information about a company's employees: their department, date of birth, salary level, and other information.  We will connect the Node.js application to this database, and we will work with the employees collection. Creating a User in MongoDB Compass Create a new user to work with the database. For testing purposes, we will assign the user administrator privileges for all databases; however, you shouldn't do this in production—it will negatively impact security. Open a MongoDB Shell terminal and run the following query: >use admin > db.createUser({ user: "Hostman", pwd: "password", roles: [ { role: "userAdmin", db: "admin" }, { role: "dbAdminAnyDatabase", db: "admin" } ] }) Output: {ok: 1} We have created a user named "Hostman" with a password "password" and will use it to connect to the database. Setup To connect a Node.js application to a MongoDB database, you need to install the additional mongodb package: npm install mongodb --savenpm install mongodb-core --save Connection The main object through which we will interact with the MongoDB database is an object of the MongoClient class. Let's import this class: const {MongoClient} = require('mongodb') And declare the DBclient object using the constructor: const MongoDBclient = new MongoClient('URI') The class constructor is given a URI as input, which contains information about the user, IP, and server port. Here's the URI structure: mongodb://login:password@IP:PORT/?authMechanism=method In the case of a database hosted on a local machine, the URI looks like this: mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT Here, we are using: Hostman as username; password as password; port 27017; DEFAULT as the authorization mechanism. Let's connect to the server with the database: const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const connect = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } connect() Output: Successfully connected to databaseConnection closed Any interactions with the database are asynchronous operations, therefore, it is necessary to use async and await. Let's look at several popular operations. Inserting documents To insert a new document, you need to execute a query to the database with document data as an argument. Inserting a single document const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const employee = { surname: 'Smith', age: 45, salary: 260000, department: 'DevRel', date_of_birth: '15/11/1977', first_name: 'John' } const Insert = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") const employees = MongoDBclient.db('testdb').collection('employees') await employees.insertOne(employee) await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } Insert() Inserting multiple documents const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const ManyEmployees = [{ surname: 'Hernandez', age: 27, salary: 160000, department: 'Legal Department', date_of_birth: '15/05/1995', first_name: 'Juan' }, { surname: 'Miles', age: 30, salary: 200000, department: 'Tech Support', date_of_birth: '06/02/1992', first_name: 'Mary' }] const Insert = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") const employees = MongoDBclient.db('testdb').collection('employees') await employees.insertMany(ManyEmployees) await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } Insert() Let's check the total number of documents in the collection after insertions: const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const Count = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") const AllDocuments = await MongoDBclient.db('testdb').collection('employees').find().toArray() console.log("Number of documents in the database:", AllDocuments.length) await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } Count() Output: Successfully connected to databaseNumber of documents in the database: 5Connection closed Querying documents To query documents in the database, use the following construction: MongoClienObject.db('dbname').collection('collectionname').operation Where: MongoClienObject is an object of the MongoClient class; dbname is the name of the database we are accessing; collectionname is the name of the collection we are accessing; operation is the query to a database or collection, for example, findOne; If the request is made directly to the database, then collection('collectionname') is not needed. Let's display all documents in the employees collection: const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const Find = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") const AllDocuments = await MongoDBclient.db('testdb').collection('employees').find().toArray() console.log(AllDocuments) await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } Find() Ouput: Connection successful [ { _id: new ObjectId("637c9cbd7025c2523a76fe64"), surname: 'Williams', age: 50, salary: 100000, department: 'marketing', date_of_birth: '15/11/1972', first_name: 'Natalie' }, { _id: new ObjectId("637ca6127025c2523a76fe65"), surname: 'Rubio', age: 35, salary: 200000, department: 'QA', date_of_birth: '12/06/1987', first_name: 'Manuel' } ] Connection closed Updating documents Updating documents is performed in the same way as the operations above. Updating a single document const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const Update = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") const employees = MongoDBclient.db('testdb').collection('employees') await employees.findOneAndUpdate({first_name: 'John'} , { $set: {first_name: "Johnny"}}) await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } Update() Updating multiple documents const {MongoClient} = require('mongodb') const MongoDBclient = new MongoClient('mongodb://Hostman:[email protected]:27017/?authMechanism=DEFAULT') const Update = async() =>{ try { await MongoDBclient.connect() console.log("Successfully connected to database") const employees = MongoDBclient.db('testdb').collection('employees') await employees.updateMany({$or:[{department: 'DevRel'},{department: 'marketing'}]} , { $set: {department: "PR"}}) await MongoDBclient.close() console.log("Connection closed") } catch (e) { console.log(e) } } Update() Conclusion MongoDB is a great tool, especially when coupled with Node.js. In this material, we used a local database, but there are other options, like cloud. At Hostman, you can deploy a MongoDB cloud database in a few seconds and start working in no time.
21 May 2024 · 7 min to read

Do you have questions,
comments, or concerns?

Our professionals are available to assist you at any moment,
whether you need help or are just unsure of where to start.
Email us
Hostman's Support