10个MongoDB面试必备问题 *
最好的MongoDB开发人员和工程师可以回答的基本问题. 在我们社区的推动下,我们鼓励专家提交问题并提供反馈.
现在聘请一名顶级MongoDB开发人员Interview Questions
就像传统的rdbms一样, 对于规范化数据,更新文档的速度很快,而对于非规范化数据,更新文档的速度相对较慢. 另一方面,在非规范化数据中读取文档速度很快,而在规范化数据中读取文档速度较慢. 非规范化的数据更难保持同步,并且占用更多的空间.
请注意,在MongoDB中,非规范化数据是更常见的期望. 这是因为rdbms具有对规范化的固有支持,并允许将数据作为单独的关注点进行管理, 而像MongoDB这样的NoSQL数据库本身并不支持规范化.
相反,规范化要求客户机应用程序自己小心地维护完整性. To help with this, 可以运行审计来确保应用程序数据符合预期的引用完整性模式.
分片和复制都涉及使用多个实例来托管数据库.
副本是具有相同数据的MongoDB实例,因此得名. 我们使用副本来增加冗余和可用性.
另一方面,对于分片,每个分片实例与其邻居拥有不同的数据. 我们使用分片进行水平扩展.
Whether we provide an _id
确定这两个命令的预期结果. 以下是每种情况的预期结果.
-
save
command while providing an_id
:在这种情况下,新提供的文档将用匹配的文档替换找到的文档_id
. -
save
命令,而不提供_id
: Inserts a new document. -
insert
command while providing an_id
: Gives aE11000 duplicate key error
列出集合、索引和重复键. -
insert
命令,而不提供_id
: Inserts a new document.
As you can see, both the insert
and save
命令的行为与此类似,只有当我们不提供 _id
.
例如,下面的命令会给我们相同的结果:
db.cars.保存({电动机:“6缸”,颜色:“黑色”})
db.cars.插入({电动机:“6缸”,颜色:“黑色”})
申请加入Toptal的发展网络
并享受可靠、稳定、远程 自由MongoDB开发人员职位
JSON (JavaScript对象表示法),类似于XML, 例如,是用于数据交换的人类可读标准. JSON已经成为网络上最广泛使用的数据交换标准. JSON支持布尔值、数字、字符串和数组等数据类型.
然而,BSON是MongoDB用来存储文档的二进制编码. 它类似于JSON,但它扩展了JSON以支持更多的数据类型,例如 Date
. 与JSON文档不同,BSON文档是有序的. BSON通常比JSON占用更少的空间,并且遍历速度更快. 由于BSON是二进制的,因此编码和解码也更快.
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 条件.
假设有一个文档,其中嵌套了如下所示的数组. 你如何插入一个有 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"
}
]
}
]
}
我们可以用下面的代码来实现,内联注释:
db.users.update(
{
"_id": ObjectId("682263"),
"houses._id":"2178123" //标识我们要更新的房子的id
},
{ "$push":
{
"houses.$.Rooms ": //确定我们想要放入的数组
{
"name": "Room 44", //这是需要推送的有效载荷
"size": "50"
}
}
}
)
假设有一个名为 users
看起来像下面这个. How can you get all houses
在"拉比亚"附近?
[
{
"_id": ObjectId("5d011c94ee66e13d34c7c388"),
"userName" : "kevin",
"email" : "kevin@lookforstudies.com",
"password" : "affdsg342",
"houses" : [
{
"name" : "Big Villa",
"neighborhood" : "Zew Ine"
},
{
"name" : "Small Villa",
"neighborhood" : "Rabia"
}
]
},
{
"_id": ObjectId("5d011c94ee66e13d34c7c387"),
"userName" : "sherif",
"email" : "sharief@lookforstudies.com",
password:“67834783ujk”,
"houses" : [
{
"name" : "New Mansion",
“邻里”:“纳斯尔城”
},
{
"name" : "Old Villa",
"neighborhood" : "Rabia"
}
]
},
]
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@lookforstudies.com",
"password" : "affdsg342",
"houses" : [
{
"name" : "Big Villa",
"neighborhood" : "Zew Ine"
},
{
"name" : "Small Villa",
"neighborhood" : "Rabia"
}
]
},
{
"_id": ObjectId("5d011c94ee66e13d34c7c387"),
"userName" : "sherif",
"email" : "sharief@lookforstudies.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"
}
]
}
]
您能发现下面两个查询的不同之处吗?
dealers.find({
"$and": [
{
"length": {
"$gt": 2000
}
},
{
"cars.weight": {
"$gte": 800
}
}
]
});
dealers.find({
"length": {
"$gt": 2000
},
"cars.weight": {
"$gte": 800
}
});
实际上,它们完全一样. MongoDB implicitly uses the $and
operator 用于逗号分隔的查询. 与最佳实践相比,使用哪一个更像是一个偏好问题.
False. All write 操作只在主服务器上进行. On the other hand, read 操作可以在任何实例上进行——从实例或主实例. 因此,只有在向副本集添加更多slave时,读取才会变得更快.
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全权决定, LLC.
寻找MongoDB开发人员?
Looking for MongoDB Developers? 看看Toptal的MongoDB开发人员.
Marcin Bodnar
Freelance MongoDB Developer
Marcin是一名专注于web开发的高级软件工程师,拥有超过15年的专业经验(在初创公司和企业环境中),并成功完成了300多个web项目. 说到发展, 他相信动机, communication, high resistance to stress, 在实现客户期望的过程中,团队文化至关重要. Marcin同样喜欢团队合作或独立工作.
Show MorePetr Rusanov
Freelance MongoDB Developer
peter是一名全栈工程师,拥有17年优化代码、成本和用户体验的经验. 他擅长为云原生服务编写安全、可读和可靠的代码. 他精通围棋和Node.js, PostgreSQL, MongoDB, Bigtable, GCP/AWS/Azure, React/Vue, Kubernetes, ArgoCD, Docker, and Terraform. peter专注于提供卓越的用户体验和优化大规模应用程序,以实现最佳性能和成本效率.
Show MoreSilvio Di Stefano
Freelance MongoDB Developer
Silvio是一位专门从事开发的软件工程师, hosting, 并维护高质量的网站. 他与世界各地的许多团队合作过, 努力提供高端的服务和支持. 他在14岁时用PHP发布了他的第一个网站,并且是TDD的倡导者.
Show MoreToptal Connects the Top 3% 世界各地的自由职业人才.
Join the Toptal community.