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@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"
}
]
},
]
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"
}
]
}
]
您能发现下面两个查询的不同之处吗?
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 for comma-separated queries. 与最佳实践相比,使用哪一个更像是一个偏好问题.
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
自由MongoDB开发人员
Marcin是一名专注于web开发的高级软件工程师,拥有超过15年的专业经验(在初创公司和企业环境中),并成功完成了300多个web项目. 说到发展, 他相信动机, communication, high resistance to stress, 在实现客户期望的过程中,团队文化至关重要. Marcin同样喜欢团队合作或独立工作.
Show MorePetr Rusanov
自由MongoDB开发人员
peter是一名全栈工程师,拥有17年优化代码、成本和用户体验的经验. 他擅长为云原生服务编写安全、可读和可靠的代码. 他精通围棋和Node.js, PostgreSQL, MongoDB, Bigtable, GCP/AWS/Azure, React/Vue, Kubernetes, ArgoCD, Docker, and Terraform. peter专注于提供卓越的用户体验和优化大规模应用程序,以实现最佳性能和成本效率.
Show MoreSilvio Di Stefano
自由MongoDB开发人员
Silvio是一位专门从事开发的软件工程师, hosting, 并维护高质量的网站. 他与世界各地的许多团队合作过, 努力提供高端的服务和支持. 他在14岁时用PHP发布了他的第一个网站,并且是TDD的倡导者.
Show MoreToptal Connects the Top 3% 世界各地的自由职业人才.
Join the Toptal community.