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

MongoDB Shell深入探索:客户端功能

2023-11-245.5k 阅读

MongoDB Shell 基础认知

MongoDB Shell 是与 MongoDB 交互的重要工具,它基于 JavaScript 构建,为用户提供了一个交互式的环境来执行数据库操作。在深入客户端功能之前,先了解一些基础操作,这有助于我们更好地理解后续复杂功能。

当我们启动 MongoDB Shell 时,实际上是启动了一个 JavaScript 环境,并且自动连接到了本地 MongoDB 实例的 test 数据库(默认情况)。例如,启动 Shell 后,我们可以简单地输入 db 命令,它会返回当前所在的数据库对象。

// 启动MongoDB Shell后,执行db命令查看当前数据库
db

这一操作背后,是 MongoDB Shell 识别 db 这个特殊变量,它始终指向当前正在使用的数据库对象。如果我们想要切换数据库,可以使用 use 命令。

// 切换到名为myDB的数据库,如果数据库不存在,后续操作会自动创建
use myDB

数据库操作功能

创建和删除数据库

在 MongoDB Shell 中,创建数据库并不像传统关系型数据库那样需要特定的创建语句。正如上面 use 命令所展示的,当我们使用 use 切换到一个不存在的数据库时,只要后续对该数据库进行写操作(比如插入文档),数据库就会被自动创建。

// 切换到newDB数据库
use newDB
// 向newDB数据库的testCollection集合中插入一个文档,这会自动创建newDB数据库(如果不存在)
db.testCollection.insertOne({name: 'example'})

删除数据库也很直接,通过 db.dropDatabase() 方法即可。这个方法会删除当前 db 变量所指向的数据库。

// 假设当前在testDB数据库,删除该数据库
db.dropDatabase()

查看数据库列表

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

show dbs

这个命令会返回当前 MongoDB 实例中所有数据库的名称及大致大小。但需要注意的是,如果一个数据库刚刚创建且没有任何数据,使用 show dbs 可能不会立即显示该数据库,直到有数据插入后才会显示。

集合操作功能

创建和删除集合

集合类似于关系型数据库中的表,是 MongoDB 中存储文档的逻辑容器。创建集合同样可以通过简单的插入操作隐式创建。例如,当我们向一个不存在的集合插入文档时,集合会自动创建。

// 向myCollection集合插入文档,如果myCollection不存在则自动创建
db.myCollection.insertOne({key: 'value'})

也可以显式创建集合,使用 db.createCollection() 方法,并可以在创建时指定一些选项,如设置集合的大小上限、是否为固定集合等。

// 显式创建名为fixedColl的固定集合,大小为5242880字节,最多容纳1000个文档
db.createCollection("fixedColl", {capped: true, size: 5242880, max: 1000})

删除集合使用 db.collection.drop() 方法,其中 collection 是要删除的集合名称。

// 删除名为myCollection的集合
db.myCollection.drop()

查看集合列表

使用 show collections 命令可以查看当前数据库中的所有集合。

show collections

文档操作功能

插入文档

插入文档是 MongoDB 最基本的操作之一。可以使用 insertOne() 方法插入单个文档,insertMany() 方法插入多个文档。

// 插入单个文档
db.users.insertOne({name: 'John', age: 30})

// 插入多个文档
db.users.insertMany([
    {name: 'Jane', age: 25},
    {name: 'Bob', age: 35}
])

查询文档

查询操作在 MongoDB 中功能强大且灵活。基本的查询使用 find() 方法,不带任何参数时会返回集合中的所有文档。

// 查询users集合中的所有文档
db.users.find()

要指定查询条件,可以在 find() 方法中传入一个查询文档。例如,查询年龄大于 30 的用户。

// 查询年龄大于30的用户
db.users.find({age: {$gt: 30}})

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

更新文档

更新文档使用 updateOne()updateMany() 方法。例如,将名字为 John 的用户年龄更新为 31。

// 更新单个文档
db.users.updateOne({name: 'John'}, {$set: {age: 31}})

$set 操作符用于指定要更新的字段和值。如果要更新多个符合条件的文档,可以使用 updateMany()

// 更新所有年龄大于30的用户,将他们的年龄加1
db.users.updateMany({age: {$gt: 30}}, {$inc: {age: 1}})

这里 $inc 操作符用于对字段值进行递增操作。

删除文档

删除文档使用 deleteOne()deleteMany() 方法。例如,删除名字为 Bob 的用户。

// 删除单个文档
db.users.deleteOne({name: 'Bob'})

如果要删除所有符合某个条件的文档,如删除所有年龄小于 25 的用户,则使用 deleteMany()

// 删除多个文档
db.users.deleteMany({age: {$lt: 25}})

高级查询功能

投影操作

投影操作允许我们在查询时指定返回文档的字段,而不是返回整个文档。通过在 find() 方法的第二个参数中指定投影文档来实现。例如,只返回用户的名字,不返回年龄。

// 只返回名字字段
db.users.find({}, {name: 1, _id: 0})

这里 1 表示包含该字段,0 表示排除该字段。需要注意的是,_id 字段默认是返回的,如果不想返回,必须显式设置为 0

排序操作

使用 sort() 方法对查询结果进行排序。例如,按年龄升序排序。

// 按年龄升序排序
db.users.find().sort({age: 1})

1 表示升序,-1 表示降序。如果要按多个字段排序,可以在 sort() 方法的参数中传入多个字段及排序方向。

// 先按年龄升序,年龄相同再按名字降序
db.users.find().sort({age: 1, name: -1})

限制和跳过操作

limit() 方法用于限制返回结果的数量,skip() 方法用于跳过指定数量的文档。例如,只返回前 5 个文档。

// 只返回前5个文档
db.users.find().limit(5)

跳过前 3 个文档,返回后面的文档。

// 跳过前3个文档
db.users.find().skip(3)

聚合操作

聚合操作允许我们对文档进行复杂的数据处理,如分组、求和、平均值计算等。聚合使用 aggregate() 方法,通过管道操作符来处理数据。

例如,计算用户的平均年龄。

db.users.aggregate([
    {$group: {_id: null, averageAge: {$avg: '$age'}}}
])

这里 $group 是聚合管道操作符,用于按指定字段分组。_id 设置为 null 表示不按任何字段分组,即对整个集合进行操作。$avg 是聚合操作符,用于计算平均值。

索引操作功能

创建索引

索引可以大大提高查询性能。在 MongoDB Shell 中,可以使用 createIndex() 方法创建索引。例如,为 users 集合的 name 字段创建一个单字段索引。

// 为name字段创建单字段索引
db.users.createIndex({name: 1})

还可以创建复合索引,即基于多个字段的索引。

// 为age和name字段创建复合索引
db.users.createIndex({age: 1, name: -1})

查看索引

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

// 查看users集合的所有索引
db.users.getIndexes()

删除索引

删除索引使用 dropIndex() 方法,传入索引名称即可。索引名称可以从 getIndexes() 的结果中获取。

// 删除名为name_1的索引
db.users.dropIndex({name: 1})

游标操作

在 MongoDB 中,查询结果通常以游标(Cursor)的形式返回。游标是一个指向查询结果集的指针,它允许我们逐步遍历结果。

当我们执行一个查询,如 db.users.find(),实际上返回的是一个游标对象。默认情况下,MongoDB Shell 会自动迭代游标并显示前 20 个文档。如果结果集超过 20 个文档,可以使用 it 命令继续显示后续文档。

// 查询users集合,返回游标对象
var cursor = db.users.find()
// 使用it命令显示游标中的下一批文档
it

我们也可以手动迭代游标,通过 hasNext() 方法判断游标是否还有下一个文档,next() 方法获取下一个文档。

var cursor = db.users.find()
while (cursor.hasNext()) {
    var doc = cursor.next()
    printjson(doc)
}

这里 printjson() 是 MongoDB Shell 中的一个函数,用于以 JSON 格式打印文档。

管理连接

连接到远程 MongoDB 实例

默认情况下,MongoDB Shell 连接到本地的 MongoDB 实例。要连接到远程实例,需要在启动 Shell 时指定主机和端口。

mongo <host>:<port>

例如,要连接到主机为 192.168.1.100,端口为 27017 的 MongoDB 实例,可以执行:

mongo 192.168.1.100:27017

如果远程实例需要认证,还需要在连接时提供用户名和密码等认证信息。

mongo 192.168.1.100:27017/admin -u <username> -p <password>

这里 -u 用于指定用户名,-p 用于指定密码,admin 表示认证数据库,有些情况下认证数据库可能是其他名称,需根据实际情况调整。

断开连接

在 MongoDB Shell 中,可以使用 quit()exit() 命令断开与 MongoDB 实例的连接并退出 Shell。

quit()

脚本执行

除了在交互式环境中执行命令,MongoDB Shell 还支持执行外部 JavaScript 脚本。这对于批量执行复杂操作非常有用。

假设我们有一个名为 script.js 的文件,内容如下:

// script.js
db = connect('192.168.1.100:27017/myDB')
db.users.insertOne({name: 'ScriptInsert', age: 40})

我们可以在命令行中使用 mongo 命令执行该脚本:

mongo script.js

在脚本中,connect() 函数用于连接到指定的 MongoDB 实例和数据库。这样我们就可以在脚本中编写复杂的数据库操作逻辑,而无需在交互式 Shell 中逐行输入。

与其他编程语言集成

虽然 MongoDB Shell 提供了强大的功能,但在实际应用开发中,通常需要将 MongoDB 与其他编程语言集成。例如,在 Node.js 中,可以使用 mongodb 驱动来操作 MongoDB。

首先,通过 npm 安装 mongodb 驱动:

npm install mongodb

然后,编写如下 Node.js 代码来连接 MongoDB 并插入文档:

const { MongoClient } = require('mongodb')

const uri = "mongodb://192.168.1.100:27017"
const client = new MongoClient(uri)

async function run() {
    try {
        await client.connect()
        const database = client.db('myDB')
        const users = database.collection('users')
        await users.insertOne({name: 'NodeInsert', age: 32})
    } finally {
        await client.close()
    }
}
run().catch(console.dir)

这段代码通过 MongoClient 连接到 MongoDB 实例,选择数据库和集合,然后插入一个文档。与 MongoDB Shell 相比,这种方式更适合在应用程序中进行数据库操作,并且可以利用编程语言的各种特性来实现复杂的业务逻辑。

通过对 MongoDB Shell 客户端功能的深入探索,我们可以更好地掌握 MongoDB 的使用,无论是简单的数据库操作,还是复杂的查询、索引管理等,都能更加得心应手,为实际应用开发提供有力支持。同时,了解与其他编程语言的集成,也拓宽了我们在不同场景下使用 MongoDB 的能力。