10 Essential MongoDB Interview Questions *

Looking for Freelance MongoDB Developer jobs? Design your lifestyle as a MongoDB developer with Toptal.

Submit an Interview Question

What are the pros and cons of normalizing data in a MongoDB database?

Just like in traditional RDBMSes, updating documents is fast for normalized data and relatively slower for denormalized data. On the other hand, reading documents is fast in denormalized data and slower for normalized data. Denormalized data is harder to keep in sync and takes up more space.

Note that in MongoDB, denormalized data is a more common expectation. This is because RDBMSes have inherent support for normalization and allow data to be managed as a separate concern, whereas NoSQL DBMSes like MongoDB do not inherently support normalization.

Instead, normalization requires that client applications carefully maintain integrity themselves. To help with this, it’s possible to run audits to ensure that app data conforms to expected patterns of referential integrity.

How are sharding and replication similar to each other in MongoDB, and how are they different?

Both sharding and replication involve using more than one instance to host the database.

Replicas are MongoDB instances with the same data, hence the name. We use replicas to increase redundancy and availability.

With sharding, on the other hand, each shard instance has different data from its neighbors. We use sharding for horizontal scaling.

What is the difference between the save and insert commands in MongoDB, and when do they act similarly?

Whether we provide an _id determines the expected result for both of these commands. Here is the expected outcome for each case.

  1. save command while providing an _id: In this case, the newly provided document replaces the document found with a matching _id.
  2. save command while not providing an _id: Inserts a new document.
  3. insert command while providing an _id: Gives a E11000 duplicate key error listing the collection, index, and duplicate key.
  4. insert command while not providing an _id: Inserts a new document.

As you can see, both the insert and save commands act similarly only when we do not provide an _id.

For example, the commands below would give us the same result:

db.cars.save({motor:"6-cylinder",color:"black"})
db.cars.insert({motor:"6-cylinder",color:"black"})

Apply to Join Toptal's Development Network

and enjoy reliable, steady, remote Freelance MongoDB Developer Jobs.

Apply as a Freelancer

What are some differences between BSON documents used in MongoDB and JSON documents in general?

JSON (JavaScript Object Notation)—like XML, for example—is a human-readable standard used for data exchange. JSON has become the most widely used standard for data exchange on the web. JSON supports data types like booleans, numbers, strings, and arrays.

BSON, however, is the binary encoding that MongoDB uses to store its documents. It is similar to JSON, but it extends JSON to support more data types, like Date. BSON documents, unlike JSON documents, are ordered. BSON usually takes less space than JSON and is faster to traverse. BSON, since it is binary, is also quicker to encode and decode.

What is the difference between the $all operator and the $in operator?

Both the $all operator and the $in operator are used to filter documents in a subarray based on a conditional. Let us assume we have the following documents in a collection.

[{
        "name": "Youssef",
        "sports": [
            "Boxing",
            "Wrestling",
            "Football"
        ]
    },
    {
        "name": "Kevin",
        "sports": [
            "Wrestling",
            "Football"
        ]
    },
    {
        "name": "Eva",
        "sports": [
            "Boxing",
            "Football"
        ]
    }
]

Using $all as shown below will return only the first two documents:

db.users.find({
    sports: {
        $all: ["Wrestling", "Football"]
    }
})

Using $in will return all three documents:

db.users.find({
    skills: {
        $in: ["Wrestling", "Football"]
    }
})

The $all operator is stricter than the $in operator. $all is comparable to an AND conditional, and likewise $in resembles an OR conditional. That is to say, $all retrieves documents that satisfy all conditions in the query array, whereas $in retrieves documents that meet any condition in the query array.

Assume there is a document with nested arrays that looks like the one below. How can you insert a “room” that has the name “Room 44” and size of “50” for a particular “house” that belongs to this user?

{
    "_id": "682263",
    "userName" : "sherif",
    "email": "sharief@aucegypt.edu",
    "password": "67834783ujk",
    "houses": [
        {
        "_id": "2178123",
        "name": "New Mansion",
        "rooms": [
            {
            "name": "4th bedroom",
            "size": "12"
            },
            {
            "name": "kitchen",
            "size": "100"
            }
        ]
        }
  ]
}

We can do so with the following code, commented inline:

db.users.update(
    { 
        "_id": ObjectId("682263"),
        "houses._id":"2178123"     // identify the id for the house that we want to update
    },
    { "$push":   
        {
            "houses.$.rooms":      // identify the array we want to push items into
                {                  
                    "name": "Room 44",      // this is the payload that needs to be pushed 
                    "size": "50"
                }
        }
    }
)

Assume there is a collection named users that looks like the one below. How can you get all houses in the “Rabia” neighborhood?

[
    {
        "_id" : ObjectId("5d011c94ee66e13d34c7c388"),
        "userName" : "kevin",
        "email" : "kevin@toptal.com",
        "password" : "affdsg342",
        "houses" : [
            {
                "name" : "Big Villa",
                "neighborhood" : "Zew Ine"
            },
            {
                "name" : "Small Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },

    {
        "_id" : ObjectId("5d011c94ee66e13d34c7c387"),
        "userName" : "sherif",
        "email" : "sharief@toptal.com",
        "password" : "67834783ujk",
        "houses" : [
            {
                "name" : "New Mansion",
                "neighborhood" : "Nasr City"
            },
            {
                "name" : "Old Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },

]

Use the $filter aggregation operator. The query is:

db.users.aggregate([
    { $match: { 'houses.neighborhood': 'Rabia' } },
    {
        $project: {
            filteredHouses: {   // This is just an alias 
                $filter: {
                    input: '$houses', // The field name we are checking
                    as: 'houseAlias', // just an alias
                    cond: { $eq: ['$$houseAlias.neighborhood', 'Rabia'] }
                }
            },
            _id: 0
        }
    }

])

The first match query will return all documents that have a house with the name Rabia. The first query in the pipeline, {$match: {'houses.neighborhood': 'Rabia'}}, will return the whole collection. This is because both users have one house in the neighborhood “Rabia”.

This is the return for the first query in the pipeline

[
    {
        "_id" : ObjectId("5d011c94ee66e13d34c7c388"),
        "userName" : "kevin",
        "email" : "kevin@toptal.com",
        "password" : "affdsg342",
        "houses" : [
            {
                "name" : "Big Villa",
                "neighborhood" : "Zew Ine"
            },
            {
                "name" : "Small Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },

    {
        "_id" : ObjectId("5d011c94ee66e13d34c7c387"),
        "userName" : "sherif",
        "email" : "sharief@toptal.com",
        "password" : "67834783ujk",
        "houses" : [
            {
                "name" : "New Mansion",
                "neighborhood" : "Nasr City"
            },
            {
                "name" : "Old Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },

]

We do not want to display other user details nor display houses other than those in Rabia, so we will use the $filter operator inside the $project operator:

{
    $project: {
        filteredHouses: {   // This is just an alias 
            $filter: {
                input: '$houses', // The field name we check
                as: 'houseAlias', // just an alias
                cond: { $eq: ['$$houseAlias.neighborhood', 'Rabia'] }
            }
        },
        _id: 0
    }
}

The $$ prefix is required on houseAlias (instead of simply one $) due to nesting.

Here is the result we obtain at the end of the pipeline:

[
    {
        "filteredHouses" : [
            {
                "name" : "Old Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },
    {
        "filteredHouses" : [
            {
                "name" : "Small Villa",
                "neighborhood" : "Rabia"
            }
        ]
    }
]

Could you catch how the two queries below are different?

dealers.find({
    "$and": [
        {
            "length": {
                "$gt": 2000
            }
        },
        {
            "cars.weight": {
                "$gte": 800
            }
        }
    ]
});

dealers.find({
    "length": {
        "$gt": 2000
    },

    "cars.weight": {
        "$gte": 800
    }
});

Actually, they are exactly the same. MongoDB implicitly uses the $and operator for comma-separated queries. Which one to use is more a matter of preference than best practices.

“Both writes and reads become faster when you add more slaves to a replica set.” Is this statement true or false? Why?

False. All write operations are done only on the master. On the other hand, read operations can be made on any instance—slave or master. Therefore, only reads become faster when you add more slaves to a replica set.

A staple feature of relational database systems is the JOIN clause. What is the equivalent in MongoDB, and does it have any known limitations?

The $lookup operator is the equivalent of JOIN.

Here is an example of a nested lookup in MongoDB.

Assume we have three collections (authors, authorInfo, and userRole) with the following data:

// authors collection
[
    {
        "_id" : ObjectId("5d0127aaee66e13d34c7c389"),
        "address" : "32 Makram Ebeid Street",
        "isActive" : true,
        "authorId" : "121"
    }
]

// authorInfo collection
[
    {
        "_id" : ObjectId("5d0f726bac65f929d0fa98b2"),
        "authorId" : "121",
        "description" : "A description"
    }
]

// userRole collection
[
    {
        "_id" : ObjectId("5d012a08ee66e13d34c7c38f"),
        "userId" : "121",
        "role" : "manager"
    }
]

What if we want to join the authors from all three collections? In the SQL world, a JOIN query for this might look like:

SELECT a._id, a.address, b.description, c.role
  FROM authors a
  INNER JOIN "authorInfo" b ON b."authorId" = a."authorId"
  INNER JOIN "userRole" c ON c."userId" = a."authorId"

But in MongoDB, here is the equivalent query:

db.authors.aggregate([

    // Join with authorInfo table
    {
        $lookup:{
            from: "authorInfo",       // connecting authorInfo collection
            localField: "authorId",   // name of field in the authors collection
            foreignField: "authorId", // name of field in the authorInfo collection
            as: "authorInfoAlias"     // any alias
        }
    },
    {   $unwind:"$authorInfoAlias" }, // use the alias here

    // Join with userRole collection
    {
        $lookup:{
            from: "userRole", 
            localField: "authorId", 
            foreignField: "userId",
            as: "authorRoleAlias"
        }
    },
    {   $unwind:"$authorRoleAlias" },
    {   
        $project: {                                          // Just projecting our data.
            _id : 1,
            address : 1,
            description : "$authorInfoAlias.description",
            role : "$authorRoleAlias.role",
        } 
    }

The $ prefix is required for aliases to work.

The result of this query is the following:

[
    {
        "_id" : ObjectId("5d0127aaee66e13d34c7c389"),
        "address" : "32 Makram Ebeid Street",
        "description" : "A description",
        "role" : "manager"
    }
]

The major drawback of the $lookup operator is that it does not work in sharded collections.

It’s worth noting that, instead of looking for a direct equivalent to JOIN, a more common approach with MongoDB developers is to simple denormalize the data, precluding the need for a JOIN equivalent.

There is more to interviewing than tricky technical questions, so these are intended merely as a guide. Not every “A” candidate worth hiring will be able to answer them all, nor does answering them all guarantee an “A” candidate. At the end of the day, hiring remains an art, a science — and a lot of work.

Submit an interview question

Submitted questions and answers are subject to review and editing, and may or may not be selected for posting, at the sole discretion of Toptal, LLC.

* All fields are required

Danial Farid

Freelance MongoDB Developer

United StatesToptal Member Since October 27, 2016

Danial has a decade of software experience mainly developing the back-end with Java and more recently full-stack. He's an expert in algorithms, data-structures, OOD, multi-threading, core Java/JavaScript, and best practices. He has implemented high-throughput cloud-based REST APIs and standalone web apps. He loves new tech and solving challenges with a focus on agility, fast delivery, and re-usability.

Show More

Marcelo Luiz Onhate

Freelance MongoDB Developer

BrazilToptal Member Since October 22, 2018

Marcelo is an experienced chief software architect specializing in converting ideas and customer needs into scalable products. He’s collaborated with multiple Fortune Global 500 companies on global-level projects. Today, he works remotely—building software solutions with world distributed collaborators. With more than a decade of experience and an entrepreneurial mindset, Marcelo will be a valuable addition to any project.

Show More

Marcin Bodnar

Freelance MongoDB Developer

PolandToptal Member Since January 11, 2016

Marcin is a senior software engineer focused on web development with over 15 years of proven professional experience (in both startups and enterprise environments) and more than 300 successful web projects. When it comes to development, he believes that motivation, communication, high resistance to stress, and team culture are crucial when bringing the clients' expectations to life. Marcin equally enjoys working in a team or independently.

Show More

Looking for MongoDB Developers?

Looking for MongoDB Developers? Check out Toptal’s MongoDB developers.

Toptal Connects the Top 3% of Freelance Talent All Over The World.

Join the Toptal community.

Learn more