Logo
Section 1 / 5

使用 MongoDB 与 Deno

了解何时使用 NoSQL 与 MongoDB。

导入

使用 MongoDB 与 Deno

了解何时使用 NoSQL 与 MongoDB。

在上一章中,我们讨论了关系型数据库(SQL)的优缺点及其一些应用场景。本章我们将使用 MongoDB 作为数据库,对非关系型数据库(NoSQL)的优缺点进行同样的分析。

NoSQL 数据库的优缺点

优点缺点
易于使用:这可能是一个主观观点,但 NoSQL 数据库(尤其是文档型数据库)对于初学者来说通常更容易搭建和使用。数据不一致:没有固定模式也可能带来问题。如果未在保存前验证必填字段,可能会导致脏数据进入系统。
灵活性:这可能是上述优点的原因之一。NoSQL 数据库不依赖于固定模式,因此更容易修改数据格式,具备更高的灵活性。索引支持有限:与 SQL 数据库相比,NoSQL 数据库的索引功能较弱,配置起来更复杂。
可扩展性:MongoDB 的横向扩展能力非常出色,配置简单且能高效完成扩展任务。其他许多 NoSQL 数据库也具有类似特性。数据冗余:在使用文档型数据库时,由于实体之间的关联关系不够明确,容易出现数据重复的情况。

应用场景

NoSQL 数据库通常用于电商系统。在这些场景中,销售的商品种类繁多,差异极大,难以设计统一的通用模式;而为每种商品单独定义模式也不现实。

使用 NoSQL 可以解决这一问题:无需担心模式限制,可以灵活存储所需的数据。不过,仍需定义一些通用的必填字段(如 ID、价格等),在大型项目中建议通过父类型和继承机制来组织结构。

在我们的示例中,将使用 NoSQL 来存储书籍、作者和评论信息。

添加数据

我们可以使用 MongoDB Compass 轻松创建集合并添加数据。如果希望使用 Mongo Shell(也可通过 MongoDB Compass 调用),可以执行以下命令:

  • 查看可用数据库:

    1show databases
  • 使用指定数据库:

    1use educative
  • 创建集合:

    1db.createCollection("books")
  • 插入一条文档:

    1db.books.insertOne({"title":"Eloquent JavaScript, Third Edition","price":32.23,"identifier":"9781593279509","description":"JavaScript lies at the heart of almost every modern web application, from social apps like Twitter to browser-based game frameworks like Phaser and Babylon. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale applications.","authorId":"61dad1982e6de6ae05c72165","reviewIds":[]})
  • 由于我们使用 db.<集合名>.insertOne,也可以替换为 insertMany、updateOne、updateMany、deleteOne、deleteMany 等方法。更多细节可查阅 MongoDB 官方文档。

...
MongoDB CRUD 操作

添加依赖

有许多不同的驱动可供选择,本例中我们将使用 denodrivers 提供的驱动。

我们需要导入用于建立连接和执行查询的客户端:

1import { Bson, MongoClient } from "https://deno.land/x/mongo/mod.ts";

我们可以使用 Bson 来定义 ObjectId,这是 MongoDB 中表示 ID 的方式。

建立连接

添加导入语句后,可以根据需要以三种不同方式建立数据库连接:

1const client = new MongoClient(); 2 3// 连接本地数据库 4await client.connect("mongodb://localhost:27017"); 5 6// 连接 Mongo Atlas 数据库 7await client.connect({ 8 db: "<db_name>", 9 tls: true, 10 servers: [ 11 { 12 host: "<db_cluster_url>", 13 port: 27017, 14 }, 15 ], 16 credential: { 17 username: "<username>", 18 password: "<password>", 19 db: "<db_name>", 20 mechanism: "SCRAM-SHA-1", 21 }, 22}); 23 24// 使用 SRV 地址连接 25await client.connect( 26 "mongodb+srv://<username>:<password>@<db_cluster_url>/<db_name>?authMechanism=SCRAM-SHA-1", 27);

让我们分析一下代码中的操作:

  • 第 1 行: 创建 MongoDB 客户端。
  • 第 4 行: 连接到本地 MongoDB 实例(选项 1)。
  • 第 7 至 22 行: 连接到 Mongo Atlas 数据库(选项 2)。
  • 第 25 至 27 行: 使用 SRV URL 连接 MongoDB 实例(选项 3)。

执行查询

本节我们将学习如何在 Deno 中访问 MongoDB 集合并运行各种查询。为了简化说明,我们以包含基本字段的书籍集合为例。

我们的数据结构如下:

1const types = gql` 2 type Book { 3 _id: String 4 title: String 5 price: Float 6 identifier: String 7 description: String 8 author: Author 9 reviews: [Review] 10 } 11 12 input BookInput { 13 title: String 14 price: Float 15 identifier: String 16 description: String 17 } 18`

访问集合

为了方便地访问集合并操作数据,我们定义一个名为 BookSchema 的接口,该接口将被 Mongo 客户端使用。

1// 定义数据结构接口 2interface BookSchema { 3 _id: Bson.ObjectId; 4 title: string; 5 price: number; 6 identifier: string; 7 description: string; 8} 9 10// 获取数据库和集合 11const db = client.database("educative"); 12const books = db.collection<BookSchema>("books");

现在我们已成功获取集合,接下来可以执行多种数据操作,如下所述。

插入数据

通过 addBook 变更操作插入新书籍,可以这样实现:

1const resolvers = { 2 //. 3 //. 4 //. 5 Mutation: { 6 addBook: async (_parent: any, { input: { title, price, identifier, description } }: any, _context: any, _info: any) => { 7 console.log(`addBook() title=(${title}), price=(${price}), identifier=(${identifier}) description=(${description})`); 8 await books.insertOne({ title, price, identifier, description }); 9 return { 10 done: true, 11 }; 12 }, 13 } 14}

获取数据

要获取数据库中所有书籍,更新 getAllBooks 查询如下:

1const resolvers = { 2 Query: { 3 getAllBooks: async () => { 4 return await books.find().toArray(); 5 }, 6 } 7}

其他操作

我们还可以使用 Mongo 库执行其他操作:

  • 更新: 使用 books.updateOne() 和 books.updateMany() 更新书籍。
  • 替换: 使用 books.replaceOne() 替换书籍。
  • 删除: 使用 books.deleteOne() 和 books.deleteMany() 删除书籍。

注意: 我们将在最终版本的接口中使用其中部分操作。

SQL:PostgreSQL 与 Deno

更新我们的模式