Skip to content
All question banks

Databases

MongoDB Questions

A comprehensive guide covering MongoDB fundamentals, CRUD operations, indexing, aggregation, sharding, and production best practices.

110 of 110 questions

MongoDB Fundamentals8

MongoDB is a leading open-source, NoSQL database program that uses a document-oriented data model rather than a traditional relational structure. It is designed to handle high volumes of data and provides high performance, high availability, and easy scalability through its distributed architecture.

MongoDB is called a NoSQL database because it does not use the traditional tabular relations of rows and columns found in SQL databases. Instead, it stores data in flexible, JSON-like BSON documents, allowing for dynamic schemas and horizontal scaling which are not typical in relational systems.

Key advantages of MongoDB include its flexible schema-less design which speeds up development, its powerful aggregation framework for data analysis, native high availability via replica sets, and horizontal scalability through sharding to handle massive datasets and high-throughput applications.

MongoDB is the appropriate choice when dealing with big data, real-time analytics, content management, or applications with rapidly changing data requirements. It is ideal for systems that need to scale horizontally or store complex, hierarchical data structures that don't fit well in flat tables.

Notable features of MongoDB include ad-hoc queries for real-time data access, indexing for improved performance, replication for data redundancy, sharding for load balancing, and a default storage engine called WiredTiger that provides document-level concurrency and efficient compression.

Relational databases use structured tables with fixed schemas and SQL for querying, while MongoDB uses flexible collections and BSON documents. MongoDB prioritizes horizontal scaling and schema flexibility, whereas RDBMS focus on vertical scaling and strict ACID compliance across structured relationships.

In a traditional SQL database, data is stored in rows within pre-defined tables linked by keys. In MongoDB, data is stored in BSON documents within collections. These documents can store nested arrays and sub-documents, allowing related data to be kept together rather than joined.

The Mongo Shell is an interactive JavaScript interface to MongoDB that allows users to query and update data and perform administrative operations. It provides a command-line environment (mongosh) where developers can directly interact with the database using JavaScript syntax.

Documents & Collections10

In MongoDB, a document is the basic unit of data, similar to a row in a relational database. A collection is a grouping of these documents, functioning like a table. However, collections do not enforce a schema, so documents within one collection can have different fields.

A MongoDB document is structured as a set of key-value pairs using a format known as BSON. The keys are strings, and the values can include various types such as other documents, arrays, and standard data types like integers, booleans, and dates.

A document is a record in MongoDB, represented in BSON (Binary JSON). It consists of field and value pairs. Documents are dynamic, meaning they don't need a pre-defined schema, allowing fields to vary between documents in the same collection for maximum flexibility.

A collection is a group of MongoDB documents. It is the equivalent of an RDBMS table but is much more flexible because it does not require a schema. Collections are usually grouped by application logic or shared data usage patterns for efficient indexing.

As defined previously, a collection is a container for BSON documents. They are stored within databases and are used to group related data. Unlike tables, collections allow for a diverse range of document structures while still allowing for centralized indexing and query optimization.

A database in MongoDB is a physical container for collections. Each database has its own set of files on the file system and its own security permissions. A single MongoDB server typically hosts multiple databases to isolate data for different applications or environments.

Internally, MongoDB uses a storage engine (like WiredTiger) to manage data on disk. It stores documents in a format called BSON (Binary JSON), which is a binary representation of JSON-like documents that is optimized for speed, space efficiency, and easy traversing during queries.

BSON stands for Binary JSON. Its significance lies in providing additional data types not found in standard JSON, such as 'Date' and 'BinData'. It is designed to be lightweight, traversable, and efficient for encoding and decoding, which enables high-performance indexing and querying in MongoDB.

MongoDB supports a wide array of data types including String, Integer, Boolean, Double, Min/Max keys, Arrays, Timestamp, Object, Null, Symbol, Date, Binary data, Regular expressions, and JavaScript code. This rich set of types allows developers to model real-world data very accurately.

Standard data types include String, Double, Boolean, and Date. More specialized types include ObjectId (for unique document IDs), Binary Data (for images/files), and Arrays or Embedded Documents, which allow for complex hierarchical relationships to be modeled within a single record without using joins.

The _id Field2

The _id field acts as the primary key for a MongoDB document. It must be unique within a collection. It allows for efficient lookups and ensures that every document can be uniquely addressed for updates, deletions, or references from other collections in the database.

The _id field is an automatically indexed unique identifier for every document. It is important because it prevents duplicate records and provides a guaranteed way to find a specific document. If not provided by the user, MongoDB generates a unique 12-byte ObjectId by default.

CRUD Operations - Insert4

You create a database by using the 'use database_name' command. Collections are created automatically when you insert the first document using 'db.collection.insert()', or you can create one explicitly using the 'db.createCollection(name)' command to specify options like size or validation rules.

Data is inserted using methods like db.collection.insertOne() for a single document or db.collection.insertMany() for an array of documents. These commands accept BSON objects and automatically add an _id field if one is not explicitly provided in the input data.

To insert a document, you use the insertOne() method on the target collection object within the shell or an SDK. You pass a JavaScript object containing the data fields. Upon success, MongoDB returns an acknowledgment containing the inserted document's unique _id.

Adding data is primarily done via the 'insert' family of commands. Developers can also use 'upsert' within an update command, which creates a new document if no document matches the query criteria, ensuring that data is either updated or added as needed.

CRUD Operations - Query/Read9

You query documents using the db.collection.find() method. You can pass a query object to filter results based on field values, use comparison operators like $gt or $lt, and use logical operators like $and or $or to build complex search criteria.

Basic querying involves using the find() method with a simple filter object, such as db.users.find({ status: 'active' }). You can also use projection to return only specific fields and use sort(), limit(), and skip() to manage the result set output.

Querying is performed by sending a BSON filter to the find() or findOne() methods. MongoDB parses this filter and uses available indexes to locate matching documents. The result is returned as a cursor, which the application can iterate through to process documents.

Queries are performed using the find() command combined with query operators. For example, to find users over age 18, you would use db.users.find({ age: { $gte: 18 } }). This approach allows for powerful, flexible data retrieval without the need for complex SQL strings.

The find() method returns a cursor that allows you to iterate through all documents matching the query. In contrast, findOne() returns only the first document that matches the query criteria as a single object, or null if no document is found, optimizing performance.

To retrieve these documents, you would execute the command: db.employees.find({ department: 'Engineering' }). This query filters the employees collection and returns all records where the department field matches the string 'Engineering' exactly.

To find the highest salary, you should sort the employees collection by salary in descending order and limit the result to one: db.employees.find().sort({ salary: -1 }).limit(1). This approach ensures you retrieve the document with the maximum value efficiently.

Standard MongoDB queries cannot sort by the length of a field directly. You must use the aggregation framework: db.collection.aggregate([{ $addFields: { nameLength: { $strLenCP: '$name' } } }, { $sort: { nameLength: -1 } }]). This calculates the length and then sorts.

This calculation requires the aggregation framework: db.employees.aggregate([{ $match: { department: 'Engineering' } }, { $group: { _id: null, avgSalary: { $avg: '$salary' } } }]). This pipeline filters by department and then computes the mathematical average across the grouped records.

CRUD Operations - Update7

Updates are performed using methods like updateOne(), updateMany(), or replaceOne(). These methods take a filter object to identify the documents and an update object using operators like $set, $inc, or $push to modify specific fields without replacing the entire document.

To update a document, call db.collection.updateOne({ _id: id }, { $set: { key: 'new_value' } }). The first parameter is the selection criteria, and the second is the modification logic. This ensures changes are applied only to the intended record efficiently.

The $set operator is used to replace the value of a field with a specified value. If the field does not exist, $set will create it. It is essential for performing partial updates, preventing the accidental overwriting of an entire BSON document.

The $set modifier is an update operator that modifies specific fields within a document. It allows you to change values or add new fields while leaving the rest of the document's data intact, which is critical for maintaining data integrity in dynamic schemas.

The updateOne() method modifies only the first document that matches the specified filter, even if multiple documents match. The updateMany() method applies the specified update logic to every single document in the collection that satisfies the query criteria simultaneously.

You would use the command: db.employees.updateOne({ name: 'John Doe' }, { $set: { salary: 90000 } }). This targeted update finds the record for John Doe and changes the salary field to the new numeric value without affecting other fields.

Use the updateMany() command: db.employees.updateMany({ department: 'Engineering' }, { $set: { bonus: 5000 } }). This operation identifies all documents in the Engineering group and adds the new bonus field with a default value of 5000 to each.

CRUD Operations - Delete2

Documents are deleted using deleteOne() or deleteMany() methods. You pass a filter object to specify which documents should be removed. For example, db.collection.deleteMany({ status: 'inactive' }) will remove all documents that match the 'inactive' status criteria permanently.

To delete a specific document, use db.collection.deleteOne({ _id: id }). By using the unique ObjectId in the filter, you ensure that only the exact intended document is removed from the collection, preventing accidental data loss across multiple records.

CRUD Operations - Syntax2

CRUD syntax follows a consistent pattern: db.collection.[action]({ filter }, { modification/data }). For Create it's insertOne(), for Read it's find(), for Update it's updateOne(), and for Delete it's deleteOne(). Most actions take a BSON query object as the primary filter.

The basic syntax relies on JavaScript-like methods. Insertion uses insert(), retrieval uses find(), modification uses update(), and removal uses remove() or delete(). Each method targets a specific collection and typically uses curly-brace query objects to define the operation scope.

Indexing10

The purpose of indexing is to increase query performance by reducing the amount of data the database must search. Without an index, MongoDB performs a collection scan, which checks every document; with an index, it can jump directly to the relevant data.

Indexing is the creation of a specialized data structure (typically a B-tree) that stores a small portion of the collection's data in an ordered way. This allows the database to locate documents extremely quickly based on the values of the indexed fields.

An index is a structure that stores a sorted list of values from specific fields. You create one using db.collection.createIndex({ field: 1 }). The '1' specifies ascending order, while '-1' specifies descending order, allowing for optimized sorting and searching.

You create an index by calling the createIndex() method on a collection. For example, db.users.createIndex({ email: 1 }, { unique: true }) creates an ascending index on the email field and enforces that no two documents can have the same email address.

MongoDB supports Single Field, Compound (multiple fields), Multikey (arrays), Geospatial (location), Text (search), and Hashed indexes. It also supports specialized indexes like TTL (Time To Live), Unique, and Partial indexes to handle specific application performance and data requirements.

A compound index is an index that includes multiple fields within a single index structure. For example, db.collection.createIndex({ last_name: 1, first_name: 1 }). This index is useful for queries that filter or sort based on both fields simultaneously, respecting the specified field order.

Geospatial indexes allow MongoDB to efficiently query data containing longitude and latitude coordinates. The '2dsphere' index supports queries on a sphere (like Earth), while '2d' indexes support flat surfaces, enabling features like finding nearby points of interest or calculating distances.

TTL (Time-To-Live) indexes are specialized single-field indexes that MongoDB uses to automatically remove documents from a collection after a certain amount of time. They are commonly used for data that has a limited lifespan, such as session logs or temporary alerts.

Geospatial indexes use specialized data structures to store coordinate data. By using a '2dsphere' index, you can perform complex queries using GeoJSON objects, such as finding all documents within a given polygon ($geoWithin) or finding the closest documents to a specific point ($near).

The explain() method provides deep insights into how MongoDB executed a query. It returns details about the query planner, whether an index was used (IXSCAN) or a collection scan occurred (COLLSCAN), and the execution time, which is vital for performance tuning and optimization.

Aggregation Framework12

Aggregation is a process of processing data records and returning computed results. It groups values from multiple documents together and can perform a variety of operations on the grouped data (like sum, average, or count) to return a single, summarized result to the user.

The Aggregation Framework is a powerful tool for data transformation and analysis. It uses a pipeline concept where documents pass through a series of stages (like $match, $group, $sort) that transform the data into an aggregated output, similar to complex JOIN and GROUP BY SQL queries.

This framework allows for multi-stage data processing. Common stages include $match for filtering, $group for categorizing, $project for reshaping documents, and $lookup for performing left-outer joins with other collections, providing a complete solution for sophisticated data reporting and analytics tasks.

An aggregation pipeline is an array of stages. Each stage performs an operation on the input documents and passes the results to the next stage. It is used for tasks like data filtering, reshaping, grouping, and performing mathematical calculations across large volumes of collection data.

You perform aggregation using the db.collection.aggregate([stage1, stage2...]) method. Each element in the array is a stage defined by an operator. For instance, you might first filter documents with $match, then group them by a specific field with $group, and finally sort the results with $sort.

The pipeline is the core of the aggregation framework. It acts as a processing chain where the output of one stage becomes the input of the next. This modular approach allows developers to build complex data processing logic by combining simple, reusable transformation stages in a sequence.

The $lookup stage is used to perform a left outer join to an unsharded collection in the same database. It allows you to combine data from two different collections based on a common field, which helps in de-normalizing data during report generation or complex queries.

Map-Reduce is a legacy data processing paradigm for condensing large volumes of data into useful aggregated results. It uses a map function to emit key-value pairs and a reduce function to combine them. While still available, the Aggregation Pipeline is now preferred for better performance and usability.

To count employees per department, use: db.employees.aggregate([{ $group: { _id: '$department', total: { $sum: 1 } } }]). This group stage uses the department field as the grouping key and increments the total counter by 1 for every document found in that category.

This pipeline groups by department, calculates the average salary, sorts the result descending, and takes the top one: db.employees.aggregate([{ $group: { _id: '$department', avg: { $avg: '$salary' } } }, { $sort: { avg: -1 } }, { $limit: 1 }]). This efficiently identifies the leading department.

Using the $year operator: db.employees.aggregate([{ $group: { _id: { $year: '$hire_date' }, count: { $sum: 1 } } }]). This pipeline extracts the year component from the hire_date field, groups the records by that year, and counts the total number of entries for each year.

Use $match with $group and $max/$min: db.employees.aggregate([{ $match: { department: 'Engineering' } }, { $group: { _id: null, maxSal: { $max: '$salary' }, minSal: { $min: '$salary' } } }]). This pipeline isolates the Engineering team and then calculates both extremes from their salary data.

Replication & High Availability6

A replica set in MongoDB is a group of mongod processes that maintain the same data set. It provides redundancy and high availability by ensuring that data is copied across multiple servers. If the primary node fails, the set automatically elects a new primary to handle write operations.

Replica sets provide data safety and high availability. They consist of one Primary node that handles all write operations and several Secondary nodes that replicate the Primary's data. This architecture allows the system to continue functioning even if some members go offline, preventing data loss.

The architecture relies on an asynchronous process where Secondaries apply the operations recorded in the Primary's oplog (operations log). All members use heartbeats to monitor each other's health, and an automated election process occurs if the current Primary becomes unreachable for any reason.

High availability is ensured through Replica Sets which provide automatic failover. Scalability is achieved through Sharding, which partitions data across multiple clusters. Together, these features allow MongoDB to handle increased load and maintain uptime during hardware failures or maintenance periods.

The oplog (operations log) is a special capped collection that keeps a rolling record of all data modifications in a replica set. Secondary members constantly poll the oplog from the primary to replicate changes, ensuring that all nodes in the set eventually reach a consistent state.

You configure high availability by deploying a replica set across multiple physical servers or data centers. By ensuring a minimum of three members (or two members plus an arbiter), you provide the quorum necessary for automated election and failover in the event of a system crash.

Sharding & Scalability7

Sharding is the process of storing data across multiple machines. MongoDB sharding works by partitioning data based on a shard key. The mongos router directs queries to the appropriate shard, while config servers store the metadata about the data distribution across the cluster.

Sharding enables horizontal scaling, allowing MongoDB to distribute massive datasets across many small servers rather than one large one. It prevents any single server from becoming a bottleneck, as read and write loads are spread out across the various shards in the environment.

Sharding involves three components: Shards (the data containers), Config Servers (metadata storage), and Query Routers (mongos). When data is written, the system uses the shard key to decide which shard receives the document. Background balancer processes ensure that data is distributed evenly across all shards.

Scale-out, or horizontal scaling, occurs by adding more shards to an existing cluster. MongoDB automatically detects the new capacity and begins migrating data chunks from existing shards to the new ones, allowing the application to handle more storage and higher throughput without downtime.

The mongos process acts as a routing service for MongoDB sharded clusters. It provides an interface to client applications, hiding the complexity of the sharded environment. It reads metadata from config servers to determine where specific data resides and routes user queries to the correct shards.

Hashed sharding uses a hashed index of a single field to distribute data. This ensures a highly even distribution of documents across the shards, even if the original field has monotonically increasing values (like timestamps), preventing 'hotspots' where one shard handles all the traffic.

Horizontal scalability is the ability to add more machines to a system to increase capacity. In MongoDB, this is implemented via Sharding. By partitioning collections across multiple replica sets, MongoDB can support petabytes of data and millions of operations per second by distributing the workload.

Storage Engines4

WiredTiger is the default engine and offers document-level concurrency and native compression, whereas the legacy MMAPv1 engine only offered collection-level locking and lacked compression. WiredTiger is much more efficient with RAM and provides higher write throughput for modern multi-core server architectures.

The main differences lie in locking mechanisms and storage efficiency. WiredTiger uses optimistic concurrency control (document-level), while MMAPv1 used pessimistic locking (collection-level). Additionally, WiredTiger supports Snappy and zlib compression to reduce disk usage, which MMAPv1 could not perform natively.

The Storage Engine API allows MongoDB to support multiple interchangeable storage engines. It provides a standard interface for the core database to interact with the underlying hardware, allowing different engines like WiredTiger or In-Memory to manage how data is actually written and retrieved from disk.

Journaling provides write-ahead logging to ensure data durability in the event of a crash. When a write occurs, it is first recorded in the journal. This adds a small performance overhead but is essential for recovery, as MongoDB can replay the journal to restore a consistent state.

Transactions & Consistency7

Transactions are a sequence of database operations that are treated as a single unit of work. In MongoDB, transactions are multi-document and ACID-compliant, meaning they guarantee that either all operations succeed together or none are applied, protecting data integrity in complex business processes.

Transactions are handled using the Session API. You start a session, call startTransaction(), execute your CRUD operations, and then call commitTransaction() to save changes or abortTransaction() to roll back. This logic is typically wrapped in a try-catch block to handle potential errors gracefully.

MongoDB handles transactions using a snapshot isolation model. When a transaction starts, it sees a consistent snapshot of the data. All changes remain private until the commit, at which point they are applied atomically across all involved collections and documents within the database.

MongoDB handles consistency through tunable read and write concerns. Write concerns (w) determine how many nodes must acknowledge a write, while read concerns determine which version of data is returned. For example, 'majority' ensures that clients always see the most durable and confirmed data.

Write concern describes the level of acknowledgment requested from MongoDB for write operations to a replica set. It can range from acknowledgment from only the primary (w: 1) to acknowledgment from a majority of voting members (w: majority), allowing developers to balance safety and speed.

Write concern is important for data durability. High write concerns prevent data loss during network partitions or primary failovers by ensuring data has reached multiple nodes before the application considers the operation successful. It is a critical setting for mission-critical applications requiring high reliability.

Consistency is ensured by using 'majority' read and write concerns and enabling causal consistency in sessions. This guarantees that an application will always read its own writes and that operations follow a logical order, preventing the visibility of stale data across different nodes in the cluster.

Schema Design & Data Modeling5

Schema design in MongoDB follows the rule: 'Data that is accessed together should be stored together'. This involves deciding between Embedding (storing related data in one document) and Referencing (using ObjectIds to link documents), based on data size, relationship type, and access patterns.

Advantages include better read performance by avoiding joins and ensuring atomic updates within a single document. Disadvantages include the risk of exceeding the 16MB document size limit and potential data duplication, which can make updates more complex if the same data exists in multiple documents.

Document validation allows you to enforce a schema on a collection level using JSON Schema. This ensures that documents inserted or updated meet specific criteria, such as required fields or data types, providing a level of structure and safety similar to relational table constraints.

Schema migrations are often handled lazily by updating documents as they are accessed, or via background scripts using the updateMany() command. Since MongoDB doesn't require a rigid schema, migrations are generally less disruptive than in RDBMS, allowing for gradual updates of document structures over time.

Data locality refers to keeping related data physically close to the application or within the same document to minimize network latency and disk I/O. By using embedded documents and sharding zones, MongoDB can ensure that queries are served by the closest available resources for maximum speed.

Performance Optimization8

Optimization involves creating appropriate indexes, using projection to return only necessary fields, and utilizing the explain() method to identify bottlenecks. Additionally, ensuring that your queries are 'covered' by indexes allows MongoDB to return results without searching the actual document files on disk.

For read-heavy loads, you should use Read Replicas to distribute traffic, implement efficient indexing to minimize scans, and use caching layers. Tunable read preference settings like 'secondaryPreferred' can also be used to offload read queries from the primary node to secondary nodes.

Optimization for writes involves using sharding to distribute the write load across multiple clusters, choosing a hashed shard key to avoid hotspots, and using SSDs for better I/O. You can also adjust write concerns to be less restrictive if some level of risk is acceptable.

Monitoring is done via tools like mongostat, mongotop, and MongoDB Atlas's built-in dashboards. Troubleshooting involves analyzing the slow query log, using the explain() method on slow queries, and checking system metrics like CPU, RAM, and Disk I/O to identify physical resource saturation.

The mongostat command provides a quick overview of the status of a running mongod or mongos instance. It shows real-time statistics for queries, updates, deletes, and inserts per second, as well as memory usage and network traffic, helping admins identify sudden spikes in load.

The mongotop command provides a method to track which collections in a MongoDB instance are consuming the most time during read and write operations. It reports statistics on a per-collection basis, allowing developers to identify 'hot' collections that may need better indexing or sharding.

The db.stats() method returns a document containing storage statistics for the database. This includes information such as the total size of data, the number of collections, the number of objects, and the total size of indexes, providing a high-level view of database resource consumption.

Database profiling collects detailed information about every operation executed against the database. By setting the profiling level, you can record operations that exceed a certain time threshold, allowing you to build a comprehensive view of performance and identify specific queries that require optimization.

Backup & Recovery4

Primary utilities include mongodump and mongorestore for logical backups, and mongoexport and mongoimport for data transfer in JSON/CSV formats. For large-scale production systems, file system snapshots and specialized services like Atlas Backup or Ops Manager are the preferred choices for disaster recovery.

The mongodump utility creates a binary export of the database's contents, while mongorestore is used to reload those exports into a live database. These are essential tools for creating portable backups and moving data between different environments, such as from Production to Development.

Data import and export are performed using mongoimport and mongoexport. These tools allow for the conversion between MongoDB BSON and external human-readable formats like JSON, CSV, or TSV, facilitating the integration of MongoDB data with third-party tools and spreadsheet applications.

Handling backups involves scheduling regular mongodumps or snapshots and storing them in a secure, off-site location. Disaster recovery plans must also include testing the restoration process periodically to ensure that the data can be recovered within the organization's Recovery Time Objective (RTO).

Advanced Features2

GridFS is a specification for storing and retrieving files that exceed the 16MB BSON document size limit. It works by splitting a large file into smaller chunks and storing them in two collections. It is used for storing videos, images, and other large binary files directly in the database.

Change streams allow applications to access real-time data changes in a collection, database, or cluster. They are used to build reactive applications, such as real-time dashboards, notification systems, or to trigger microservices and external ETL processes whenever data is modified in MongoDB.

Security & Authentication1

Best practices include enabling authentication, using Role-Based Access Control (RBAC), encrypting data at rest and in transit (TLS), and disabling HTTP interfaces. Additionally, you should restrict network access using firewalls and VPC peering to ensure that only authorized clients can reach the database server.

Related