10个MongoDB面试必备问题 *

最好的MongoDB开发人员和工程师可以回答的基本问题. 在我们社区的推动下,我们鼓励专家提交问题并提供反馈.

现在聘请一名顶级MongoDB开发人员
Toptal logo是顶级自由软件开发人员的专属网络吗, designers, finance experts, product managers, 和世界上的项目经理. 顶级公司雇佣Toptal自由职业者来完成他们最重要的项目.

Interview Questions

1.

在MongoDB数据库中规范化数据的优缺点是什么?

View answer

就像传统的rdbms一样, 对于规范化数据,更新文档的速度很快,而对于非规范化数据,更新文档的速度相对较慢. 另一方面,在非规范化数据中读取文档速度很快,而在规范化数据中读取文档速度较慢. 非规范化的数据更难保持同步,并且占用更多的空间.

请注意,在MongoDB中,非规范化数据是更常见的期望. 这是因为rdbms具有对规范化的固有支持,并允许将数据作为单独的关注点进行管理, 而像MongoDB这样的NoSQL数据库本身并不支持规范化.

相反,规范化要求客户机应用程序自己小心地维护完整性. To help with this, 可以运行审计来确保应用程序数据符合预期的引用完整性模式.

2.

在MongoDB中,分片和复制是如何相互相似的,它们有什么不同?

View answer

分片和复制都涉及使用多个实例来托管数据库.

副本是具有相同数据的MongoDB实例,因此得名. 我们使用副本来增加冗余和可用性.

另一方面,对于分片,每个分片实例与其邻居拥有不同的数据. 我们使用分片进行水平扩展.

3.

的区别是什么 save and insert 命令在MongoDB中,以及何时它们的行为类似?

View answer

Whether we provide an _id 确定这两个命令的预期结果. 以下是每种情况的预期结果.

  1. save command while providing an _id:在这种情况下,新提供的文档将用匹配的文档替换找到的文档 _id.
  2. save 命令,而不提供 _id: Inserts a new document.
  3. insert command while providing an _id: Gives a E11000 duplicate key error 列出集合、索引和重复键.
  4. insert 命令,而不提供 _id: Inserts a new document.

As you can see, both the insert and save 命令的行为与此类似,只有当我们不提供 _id.

例如,下面的命令会给我们相同的结果:

db.cars.保存({电动机:“6缸”,颜色:“黑色”})
db.cars.插入({电动机:“6缸”,颜色:“黑色”})

申请加入Toptal的发展网络

并享受可靠、稳定、远程 自由MongoDB开发人员职位

Apply as a Freelancer
4.

在MongoDB和JSON文档中使用的BSON文档之间有什么区别?

View answer

JSON (JavaScript对象表示法),类似于XML, 例如,是用于数据交换的人类可读标准. JSON已经成为网络上最广泛使用的数据交换标准. JSON支持布尔值、数字、字符串和数组等数据类型.

然而,BSON是MongoDB用来存储文档的二进制编码. 它类似于JSON,但它扩展了JSON以支持更多的数据类型,例如 Date. 与JSON文档不同,BSON文档是有序的. BSON通常比JSON占用更少的空间,并且遍历速度更快. 由于BSON是二进制的,因此编码和解码也更快.

5.

的区别是什么 $all operator and the $in operator?

View answer

Both the $all operator and the $in 操作符用于根据条件筛选子数组中的文档. 假设集合中有以下文档.

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

Using $all 如下所示将只返回前两个文档:

db.users.find({
    sports: {
        $all:[“摔跤”,“足球”]
    }
})

Using $in 将返回所有三个文档:

db.users.find({
    skills: {
        $in:[“摔跤”,“足球”]
    }
})

The $all 操作符比 $in operator. $all is comparable to an AND conditional, and likewise $in resembles an OR conditional. That is to say, $all 检索满足的文档 all 条件,而 $in 检索满足的文档 any 条件.

6.

假设有一个文档,其中嵌套了如下所示的数组. 你如何插入一个有 name “Room 44” and size 对于属于该用户的特定“房子”的值为“50”?

{
    "_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"
            }
        ]
        }
  ]
}
View answer

我们可以用下面的代码来实现,内联注释:

db.users.update(
    { 
        "_id": ObjectId("682263"),
        "houses._id":"2178123" //标识我们要更新的房子的id
    },
    { "$push":   
        {
            "houses.$.Rooms ": //确定我们想要放入的数组
                {                  
                    "name": "Room 44", //这是需要推送的有效载荷 
                    "size": "50"
                }
        }
    }
)
7.

假设有一个名为 users 看起来像下面这个. How can you get all houses 在"拉比亚"附近?

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

    {
        "_id": ObjectId("5d011c94ee66e13d34c7c387"),
        "userName" : "sherif",
        "email" : "sharief@goudounet.com",
        password:“67834783ujk”,
        "houses" : [
            {
                "name" : "New Mansion",
                “邻里”:“纳斯尔城”
            },
            {
                "name" : "Old Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },

]

View answer

Use the $filter aggregation operator. The query is:

db.users.aggregate([
    { $match: { 'houses.neighborhood': 'Rabia' } },
    {
        $project: {
            filteredHouses:{//这只是一个别名 
                $filter: {
                    input: '$houses', //我们要检查的字段名
                    如:'houseAlias', //只是一个别名
                    cond: {$eq: ['$$houseAlias.neighborhood', 'Rabia'] }
                }
            },
            _id: 0
        }
    }

])

第一个匹配查询将返回所有具有同名房屋的文档 Rabia. 管道中的第一个查询, {$match: {'houses.neighborhood': 'Rabia'}},将退还全部藏品. 这是因为两个用户在“Rabia”附近都有一所房子。.

这是管道中第一个查询的返回值

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

    {
        "_id": ObjectId("5d011c94ee66e13d34c7c387"),
        "userName" : "sherif",
        "email" : "sharief@goudounet.com",
        password:“67834783ujk”,
        "houses" : [
            {
                "name" : "New Mansion",
                “邻里”:“纳斯尔城”
            },
            {
                "name" : "Old Villa",
                "neighborhood" : "Rabia"
            }
        ]
    },

]

我们不想显示其他用户详细信息,也不想显示除Rabia以外的房屋, so we will use the $filter operator inside the $project operator:

{
    $project: {
        filteredHouses:{//这只是一个别名 
            $filter: {
                input: '$houses', //我们检查的字段名
                如:'houseAlias', //只是一个别名
                cond: {$eq: ['$$houseAlias.neighborhood', 'Rabia'] }
            }
        },
        _id: 0
    }
}

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

下面是我们在管道末端得到的结果:

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

您能发现下面两个查询的不同之处吗?

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

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

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

实际上,它们完全一样. MongoDB implicitly uses the $and operator for comma-separated queries. 与最佳实践相比,使用哪一个更像是一个偏好问题.

9.

“当你向副本集添加更多的slave时,写和读都会变得更快.这个说法是对还是错? Why?

View answer

False. All write 操作只在主服务器上进行. On the other hand, read 操作可以在任何实例上进行——从实例或主实例. 因此,只有在向副本集添加更多slave时,读取才会变得更快.

10.

关系数据库系统的一个主要特性是 JOIN clause. 在MongoDB中等效的是什么,它是否有任何已知的限制?

View answer

The $lookup operator is the equivalent of JOIN.

下面是MongoDB中嵌套查找的一个示例.

假设我们有三个集合(authors, authorInfo, and userRole) with the following data:

// authors collection
[
    {
        "_id": ObjectId("5d0127aaee66e13d34c7c389"),
        “地址”:“Makram Ebeid街32号”,
        "isActive" : true,
        "authorId" : "121"
    }
]

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

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

如果我们想加入所有三个集合的作者呢? In the SQL world, a JOIN 对此的查询可能如下所示:

SELECT a._id, a.address, b.description, c.role
  FROM authors a
  INNER JOIN "authorInfo" b ON."authorId" = a."authorId"
  内部连接“userRole”c ON."userId" = a."authorId"

但在MongoDB中,这里是等效的查询:

db.authors.aggregate([

    //与authorInfo表连接
    {
        $lookup:{
            from: "authorInfo", //连接authorInfo集合
            localField: "authorId", //作者集合中的字段名
            foreignField: "authorId", // authorInfo集合中的字段名
            as: "authorInfoAlias" //任意别名
        }
    },
    {$unwind:"$authorInfoAlias"}, //在这里使用别名

    //连接userRole集合
    {
        $lookup:{
            from: "userRole", 
            localField: "authorId", 
            foreignField: "userId",
            as: "authorRoleAlias"
        }
    },
    {$unwind:"$authorRoleAlias"},
    {   
        $project:{//只是投影我们的数据.
            _id : 1,
            address : 1,
            description: "$authorInfoAlias ..description",
            role : "$authorRoleAlias.role",
        } 
    }

The $ 前缀是别名工作所必需的.

查询的结果如下:

[
    {
        "_id": ObjectId("5d0127aaee66e13d34c7c389"),
        “地址”:“Makram Ebeid街32号”,
        "description": "描述";
        "role" : "manager"
    }
]

The major drawback of the $lookup 操作符不能在分片集合中工作.

值得注意的是,不是寻找的直接等价物 JOIN, MongoDB开发人员更常用的方法是简单地对数据进行反规范化, precluding the need for a JOIN equivalent.

面试不仅仅是棘手的技术问题, 所以这些只是作为一个指南. 并不是每一个值得雇佣的“A”候选人都能回答所有的问题, 回答所有问题也不能保证成为A级考生. At the end of the day, 招聘仍然是一门艺术,一门科学,需要大量的工作.

Why Toptal

厌倦了面试候选人? 不知道该问什么才能让你得到一份好工作?

让Toptal为你找到最合适的人.

现在聘请一名顶级MongoDB开发人员

我们的MongoDB开发者专属网络

希望找到一份MongoDB开发人员的工作?

让Toptal为你找到合适的工作.

申请成为MongoDB开发人员

工作机会从我们的网络

提出面试问题

提交的问题和答案将被审查和编辑, 并可能会或可能不会选择张贴, 由Toptal全权决定, LLC.

* All fields are required

寻找MongoDB开发人员?

Looking for MongoDB Developers? 看看Toptal的MongoDB开发人员.

Marcin Bodnar

自由MongoDB开发人员

PolandToptal Member Since March 1, 2019

Marcin是一名专注于web开发的高级软件工程师,拥有超过15年的专业经验(在初创公司和企业环境中),并成功完成了300多个web项目. 说到发展, 他相信动机, communication, high resistance to stress, 在实现客户期望的过程中,团队文化至关重要. Marcin同样喜欢团队合作或独立工作.

Show More

Petr Rusanov

自由MongoDB开发人员

NetherlandsToptal Member Since October 19, 2015

peter是一名全栈工程师,拥有17年优化代码、成本和用户体验的经验. 他擅长为云原生服务编写安全、可读和可靠的代码. 他精通围棋和Node.js, PostgreSQL, MongoDB, Bigtable, GCP/AWS/Azure, React/Vue, Kubernetes, ArgoCD, Docker, and Terraform. peter专注于提供卓越的用户体验和优化大规模应用程序,以实现最佳性能和成本效率.

Show More

Silvio Di Stefano

自由MongoDB开发人员

FranceToptal Member Since November 29, 2013

Silvio是一位专门从事开发的软件工程师, hosting, 并维护高质量的网站. 他与世界各地的许多团队合作过, 努力提供高端的服务和支持. 他在14岁时用PHP发布了他的第一个网站,并且是TDD的倡导者.

Show More

Toptal Connects the Top 3% 世界各地的自由职业人才.

Join the Toptal community.

Learn more