MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MongoDB Shell使用技巧大揭秘

2023-09-077.9k 阅读

一、MongoDB Shell 基础操作技巧

1.1 连接 MongoDB 实例

在使用 MongoDB Shell 之前,首先要连接到 MongoDB 实例。最简单的方式是在命令行中直接输入 mongo 命令,这会尝试连接到本地默认端口(27017)的 MongoDB 实例。

mongo

如果 MongoDB 实例运行在非默认端口或者远程主机上,可以指定主机和端口。例如,连接到运行在 192.168.1.100 且端口为 27018 的实例:

mongo 192.168.1.100:27018

如果 MongoDB 实例开启了身份验证,连接时需要提供用户名和密码。假设数据库名称为 admin,用户名 myuser,密码 mypassword

mongo 192.168.1.100:27018/admin -u myuser -p mypassword

1.2 选择数据库

连接到 MongoDB 实例后,需要选择要操作的数据库。可以使用 use 命令来切换数据库。如果指定的数据库不存在,MongoDB 会在首次插入数据时自动创建该数据库。

use mydatabase

1.3 查看数据库列表

要查看当前 MongoDB 实例中的所有数据库,可以使用 show dbs 命令。

show dbs

1.4 创建和删除集合

集合类似于关系型数据库中的表,是 MongoDB 中存储文档的容器。创建集合可以使用 db.createCollection() 方法。例如,创建一个名为 mycollection 的集合:

db.createCollection("mycollection")

删除集合则使用 drop() 方法。假设当前选择的数据库中有一个名为 mycollection 的集合,删除它的操作如下:

db.mycollection.drop()

二、文档操作技巧

2.1 插入文档

插入文档是向集合中添加数据的操作。可以使用 insertOne() 方法插入单个文档,或者使用 insertMany() 方法插入多个文档。

插入单个文档示例:

db.mycollection.insertOne({
    "name": "John",
    "age": 30,
    "city": "New York"
})

插入多个文档示例:

db.mycollection.insertMany([
    {
        "name": "Jane",
        "age": 25,
        "city": "Los Angeles"
    },
    {
        "name": "Bob",
        "age": 35,
        "city": "Chicago"
    }
])

2.2 查询文档

查询文档是 MongoDB 中最常用的操作之一。使用 find() 方法可以从集合中检索文档。

查询集合中的所有文档:

db.mycollection.find()

查询符合特定条件的文档,例如查询年龄大于 30 的文档:

db.mycollection.find({ "age": { $gt: 30 } })

$gt 是 MongoDB 的比较操作符,表示 “大于”。还有其他常用的比较操作符,如 $lt(小于)、$gte(大于等于)、$lte(小于等于)、$eq(等于)、$ne(不等于)等。

2.3 更新文档

更新文档可以使用 updateOne()updateMany() 方法。updateOne() 方法只会更新符合条件的第一个文档,而 updateMany() 方法会更新所有符合条件的文档。

假设要将 mycollection 中名字为 “John” 的文档的年龄更新为 31:

db.mycollection.updateOne(
    { "name": "John" },
    { $set: { "age": 31 } }
)

$set 操作符用于指定要更新的字段和值。如果要更新多个文档,例如将所有城市为 “New York” 的文档的年龄加 1:

db.mycollection.updateMany(
    { "city": "New York" },
    { $inc: { "age": 1 } }
)

$inc 操作符用于对数值类型的字段进行增减操作。

2.4 删除文档

删除文档可以使用 deleteOne()deleteMany() 方法。deleteOne() 方法删除符合条件的第一个文档,deleteMany() 方法删除所有符合条件的文档。

例如,删除 mycollection 中名字为 “Bob” 的文档:

db.mycollection.deleteOne({ "name": "Bob" })

删除所有城市为 “Los Angeles” 的文档:

db.mycollection.deleteMany({ "city": "Los Angeles" })

三、聚合操作技巧

3.1 聚合框架简介

MongoDB 的聚合框架提供了强大的数据处理能力,可以对集合中的文档进行分组、统计、过滤等复杂操作。聚合操作使用 aggregate() 方法,通过管道(pipeline)来处理数据。管道由多个阶段(stage)组成,每个阶段对输入数据进行特定的处理,并将处理结果传递给下一个阶段。

3.2 常用聚合阶段

3.2.1 $match 阶段

$match 阶段用于过滤文档,只允许符合条件的文档进入下一个阶段。它的语法和 find() 方法中的查询条件类似。

例如,要从 mycollection 中筛选出年龄大于 30 的文档,并对这些文档进行后续聚合操作:

db.mycollection.aggregate([
    { $match: { "age": { $gt: 30 } } }
])

3.2.2 $group 阶段

$group 阶段用于按指定的字段对文档进行分组,并可以对每个组进行统计操作。在 $group 阶段中,_id 字段指定分组依据,其他字段使用聚合表达式进行统计。

例如,按城市统计人数:

db.mycollection.aggregate([
    {
        $group: {
            _id: "$city",
            count: { $sum: 1 }
        }
    }
])

这里 _id 设置为 $city,表示按城市分组。$sum 是一个聚合表达式,用于对每个组中的文档进行计数。

3.2.3 $project 阶段

$project 阶段用于指定输出文档的字段。可以选择保留、排除或重命名字段,也可以使用表达式创建新字段。

例如,要输出 mycollection 中每个人的名字和年龄,并创建一个新字段 isAdult 表示是否成年:

db.mycollection.aggregate([
    {
        $project: {
            name: 1,
            age: 1,
            isAdult: { $gte: ["$age", 18] }
        }
    }
])

这里 1 表示包含该字段,$gte 是一个比较表达式,用于判断年龄是否大于等于 18。

3.2.4 $sort 阶段

$sort 阶段用于对文档进行排序。可以按升序(1)或降序(-1)对指定字段进行排序。

例如,按年龄降序排列 mycollection 中的文档:

db.mycollection.aggregate([
    { $sort: { "age": -1 } }
])

3.3 复杂聚合示例

假设 mycollection 中有如下结构的文档,表示学生的成绩信息:

{
    "name": "Alice",
    "subjects": [
        { "name": "Math", "score": 85 },
        { "name": "English", "score": 90 }
    ]
}

要统计每个学生的平均成绩,并按平均成绩降序排列,可以使用如下聚合操作:

db.mycollection.aggregate([
    {
        $unwind: "$subjects"
    },
    {
        $group: {
            _id: "$name",
            totalScore: { $sum: "$subjects.score" },
            subjectCount: { $sum: 1 }
        }
    },
    {
        $project: {
            name: "$_id",
            averageScore: { $divide: ["$totalScore", "$subjectCount"] },
            _id: 0
        }
    },
    {
        $sort: { "averageScore": -1 }
    }
])

这里首先使用 $unwind 阶段将 subjects 数组展开,然后通过 $group 阶段计算每个学生的总成绩和科目数,接着在 $project 阶段计算平均成绩并调整输出字段,最后使用 $sort 阶段按平均成绩降序排列。

四、索引操作技巧

4.1 索引的重要性

索引在 MongoDB 中起着至关重要的作用,它可以显著提高查询性能。通过创建合适的索引,可以减少查询时需要扫描的文档数量,从而加快查询速度。

4.2 创建索引

可以使用 createIndex() 方法在集合上创建索引。

创建单字段索引,例如在 mycollection 集合的 name 字段上创建升序索引:

db.mycollection.createIndex({ "name": 1 })

创建复合索引,假设要在 agecity 字段上创建复合索引:

db.mycollection.createIndex({ "age": 1, "city": -1 })

这里第一个字段 age 按升序排列,第二个字段 city 按降序排列。

4.3 查看索引

使用 getIndexes() 方法可以查看集合上已有的索引。

db.mycollection.getIndexes()

4.4 删除索引

要删除索引,可以使用 dropIndex() 方法。例如,删除 mycollection 集合上名为 name_1 的索引(索引名可以从 getIndexes() 的结果中获取):

db.mycollection.dropIndex("name_1")

如果要删除集合上的所有索引,可以使用 dropIndexes() 方法:

db.mycollection.dropIndexes()

五、高级查询技巧

5.1 正则表达式查询

MongoDB 支持使用正则表达式进行查询。这在处理文本搜索等场景中非常有用。

例如,要查询 mycollection 中名字以 “J” 开头的文档:

db.mycollection.find({ "name": /^J/ })

这里 /^J/ 是一个正则表达式,表示以 “J” 开头。

5.2 数组查询

当文档中包含数组字段时,有多种查询方式。

假设 mycollection 中有如下文档:

{
    "name": "Charlie",
    "hobbies": ["reading", "swimming", "painting"]
}

要查询 hobbies 数组中包含 “swimming” 的文档:

db.mycollection.find({ "hobbies": "swimming" })

如果要查询 hobbies 数组中包含多个特定元素的文档,可以使用 $all 操作符。例如,查询同时包含 “reading” 和 “painting” 的文档:

db.mycollection.find({ "hobbies": { $all: ["reading", "painting"] } })

5.3 嵌套文档查询

对于嵌套结构的文档,查询时需要指定完整的路径。

假设 mycollection 中有如下文档:

{
    "name": "David",
    "address": {
        "city": "Boston",
        "zip": "02101"
    }
}

要查询地址城市为 “Boston” 的文档:

db.mycollection.find({ "address.city": "Boston" })

六、管理操作技巧

6.1 查看服务器状态

使用 db.serverStatus() 方法可以获取 MongoDB 服务器的当前状态信息,包括内存使用、连接数、操作统计等。

db.serverStatus()

6.2 备份与恢复

MongoDB 提供了 mongodumpmongorestore 工具来进行数据备份和恢复。

备份数据库,假设要备份 mydatabase 数据库到 /backup/mydatabase 目录:

mongodump --uri="mongodb://192.168.1.100:27018/mydatabase -u myuser -p mypassword" --out=/backup/mydatabase

恢复数据库,假设备份数据位于 /backup/mydatabase 目录,恢复到 mydatabase 数据库:

mongorestore --uri="mongodb://192.168.1.100:27018/mydatabase -u myuser -p mypassword" /backup/mydatabase

6.3 用户管理

在 MongoDB 中,可以使用 db.createUser() 方法创建用户,使用 db.updateUser() 方法更新用户信息,使用 db.dropUser() 方法删除用户。

创建用户示例,假设要在 admin 数据库中创建一个名为 newuser,密码为 newpassword,具有 readWriteAnyDatabase 角色的用户:

use admin
db.createUser({
    user: "newuser",
    pwd: "newpassword",
    roles: [ "readWriteAnyDatabase" ]
})

七、性能优化技巧

7.1 合理使用索引

确保查询条件中使用的字段上有合适的索引。避免在索引字段上使用函数,因为这会导致索引失效。例如,不要使用 db.mycollection.find({ "age": { $gt: Math.pow(2, 3) } }),而应预先计算好值再进行查询。

7.2 批量操作

尽量使用批量操作方法,如 insertMany()updateMany()deleteMany(),而不是多次执行单个操作。这样可以减少客户端与服务器之间的通信开销,提高性能。

7.3 优化聚合操作

在聚合操作中,尽量将 $match 阶段放在前面,以尽早过滤掉不需要的文档,减少后续阶段的处理数据量。同时,避免在聚合管道中使用过多的阶段,因为每个阶段都会带来一定的性能开销。

7.4 监控与分析

使用 MongoDB 提供的性能分析工具,如 db.setProfilingLevel()db.system.profile.find(),来监控和分析数据库操作的性能。通过分析性能数据,可以找出性能瓶颈并进行针对性优化。

八、脚本编写技巧

8.1 编写 JavaScript 脚本

MongoDB Shell 支持执行 JavaScript 脚本。可以将一系列的 MongoDB 操作编写成一个 JavaScript 文件,然后在 Shell 中执行。

例如,创建一个名为 script.js 的文件,内容如下:

// 连接到 MongoDB 实例
var conn = new Mongo("192.168.1.100:27018");
var db = conn.getDB("mydatabase");

// 插入一个文档
db.mycollection.insertOne({
    "name": "Eve",
    "age": 28,
    "city": "Seattle"
});

// 查询所有文档
var cursor = db.mycollection.find();
while (cursor.hasNext()) {
    printjson(cursor.next());
}

在 Shell 中执行该脚本:

mongo script.js

8.2 传递参数到脚本

可以通过在命令行中传递参数的方式,使脚本更加灵活。例如,修改 script.js 如下:

// 获取命令行参数
var args = Array.prototype.slice.call(arguments, 0);
var name = args[0];
var age = parseInt(args[1]);
var city = args[2];

// 连接到 MongoDB 实例
var conn = new Mongo("192.168.1.100:27018");
var db = conn.getDB("mydatabase");

// 插入一个文档
db.mycollection.insertOne({
    "name": name,
    "age": age,
    "city": city
});

// 查询所有文档
var cursor = db.mycollection.find();
while (cursor.hasNext()) {
    printjson(cursor.next());
}

在 Shell 中执行脚本并传递参数:

mongo script.js "Frank" 32 "Denver"

通过以上技巧,能更高效地使用 MongoDB Shell,无论是进行日常开发、数据处理,还是系统管理等工作。熟练掌握这些技巧,将有助于充分发挥 MongoDB 的强大功能,提升应用程序的性能和稳定性。