🌱 10 分钟内使用 MongoDB Atlas 云、Node 和 Express 完成 REST API 云设置连接到数据库 CRUD 路由 Node 研讨会

2025-05-25

🌱 10 分钟内使用 MongoDB Atlas 云、Node 和 Express 完成 REST API

云设置

连接到数据库

CRUD 路线

节点研讨会

这次,让我们把数据搬到云端吧!💾 ☁。还有什么比免费的云数据库
更好的方法呢? 我们将使用Mongo DB Atlas的免费集群。

什么是 Mongo DB Atlas?

Mongo DB Atlas 是 AWS、Azure 和 GCP 上提供的完全托管的数据库即服务

在 Atlas 之前,我使用过mLab。mLab去年被 MongoDB 收购。与 mLab 非常相似,MongoDB Atlas 是获取云 MongoDB 实例最简单的方式。

为什么?

  • 💲 0 美元:我不是 MongoDB 的广告商,但我喜欢这项服务,而且它的价格也实惠❌🔨🐖,因为……它最高 ​​512MB 的存储空间是无附加条件的免费。非常适合小型业余项目!

  • 🏃‍♂️快速、简单、快捷:无需安装和配置文件。注册并创建集群(只需 5 分钟)后,一切就绪。

  • 它在云端:它不以 Mongo 服务的形式在你的机器上运行。也不像 那样存储在磁盘文件中diskdb。你可以从任何地方通过 Atlas Web 应用进行管理。对于你的应用,你只需要一个连接 URL 即可访问数据库。

  • 😎非常酷的用户界面:Atlas 仪表板非常直观,首次使用的用户会发现它很容易通过视觉提示和步骤使用。

云设置

当您执行此操作时,实际的 Atlas UI 屏幕截图可能会有细微的差异,但所描述的步骤应该可以让您获得相同的结果。

1. 首先在这里注册:

https://www.mongodb.com/cloud/atlas/register

2. 创建免费层级的Starter Cluster

免费的Starter Cluster M0配备 512 MB 存储空间、共享 RAM 和 vCPU。

对于我们的启动 Node 项目来说这应该足够了。

  • 集群区域:您可以选择任何提供商(AWS、Google、Azure)以及距离您最近且提供免费套餐的区域。对我来说,它是 AWS us-east-1。

  • 您可以将其余部分保留为免费默认值。

  • 创建集群。

创建和配置可能需要几分钟

  • 随后,仪表板出现,其侧面板包含管理集群所需的所有选项。

3. 连接集群

在我们刚刚创建的集群中点击[连接]。

出现的对话框提供以下选项:

  1. 将您的 IP 地址列入白名单
  2. 创建 MongoDB 用户

3.1 白名单IP地址

白名单意味着只允许选定的(因此受信任的)实体访问

  • [添加您当前的 IP 地址],它会自动获取您当前的公共 IP 地址。您也可以选择添加描述,例如“我的家庭 IP 地址”。

    • ❗ 切换 WiFi 时,请记得再次执行此步骤,例如从咖啡店移动到家庭 WiFi 时。
    • 💡 如果您使用公共 Wi-Fi,您可以使用https://whatismyipaddress.com/之类的服务来获取您的 IPv4 公共地址,因为ipconfig或者ifconfig可能只会给您内部网络地址。
    • 💣您可以使用它在任何地方0.0.0.0/0启用所有 IP 地址,这简化了此过程,但却使其非常不安全。

3.2 创建管理员用户。

输入你的用户名密码。这将是第一个管理员(“root”)用户,然后[创建 MongoDB 用户](https://mongodb.io/users/)。

  • 请保留这些凭证,因为我们稍后会使用它们。

  • 关闭窗口。我们稍后会连接到集群。

4. 📃 添加示例数据

从集群视图中,单击 [集合],然后单击 [添加我自己的数据]

  • 与上一课相同,我们使用:
    • 数据库名称:data
    • 集合名称:movies

🎥 本系列电影来自 IMDB。您可以使用id任何电影页面网址。例如,在“狮子王”页面中https://www.imdb.com/title/tt0110357idtt0110357

插入文档

  • _id像以前一样插入电影条目 - 保留Atlas 提供的内容,因为这是内部的

  • 现在我们在仪表板中看到了插入的数据。根据需要添加更多数据

完美!现在我们拿到数据了。是时候连接集群了。

5. 🔌 连接到集群

返回到集群视图,然后单击我们的集群中的连接。

选择[连接您的应用程序]

保留默认的 Node.js 版本 3+

复制连接字符串。我们将在下一步中使用它。

现在我们准备深入研究代码了!

潜水

连接到数据库

1. 从这里获取上一课的启动代码:

https://github.com/lenmorld/devto_posts/tree/master/quick_node_express_diskdb

  1. 安装mongodb驱动程序
$ npm install mongodb

2. 在应用程序根目录中创建一个名为 的新文件db.js

使用此代码片段,并替换CONNECTION_STRING_FROM_ATLAS为您的连接字符串。

它看起来应该有点像这样
mongodb+srv://myusername:mypassword@cluster0-somelocation.mongodb.net/test?retryWrites=true&w=majority

// db.js

// mongodb driver
const MongoClient = require("mongodb").MongoClient;

const dbConnectionUrl = "CONNECTION_STRING_FROM_ATLAS";

function initialize(
    dbName,
    dbCollectionName,
    successCallback,
    failureCallback
) {
    MongoClient.connect(dbConnectionUrl, function(err, dbInstance) {
        if (err) {
            console.log(`[MongoDB connection] ERROR: ${err}`);
            failureCallback(err); // this should be "caught" by the calling function
        } else {
            const dbObject = dbInstance.db(dbName);
            const dbCollection = dbObject.collection(dbCollectionName);
            console.log("[MongoDB connection] SUCCESS");

            successCallback(dbCollection);
        }
    });
}

module.exports = {
    initialize
};
  1. 该函数接受我们的云数据库详细信息(数据库名称和集合名称)和回调。
  2. 然后它使用驱动方法连接到我们的云数据库MongoClient
  3. 一旦成功,它就会调用successCallback传递对象dbCollection
    • 任何失败都会被抛出failureCallback
  4. 我们将使用它dbCollection来执行 mongodb 命令。

回到我们的服务器,我们将server.js从头开始。

我们将使用云数据库连接而不是diskdb

// server.js

const express = require("express");
const server = express();

const body_parser = require("body-parser");

// parse JSON (application/json content-type)
server.use(body_parser.json());

const port = 4000;

// << db setup >>
const db = require("./db");
const dbName = "data";
const collectionName = "movies";

// << db init >>

server.listen(port, () => {
    console.log(`Server listening at ${port}`);
});

在中<< db setup >>,我们导入db.js(使用我们的initialize方法),并为数据库的信息定义变量。

4.初始化数据库连接。

// db.js
...
// << db init >>
db.initialize(dbName, collectionName, function(dbCollection) { // successCallback
    // get all items
    dbCollection.find().toArray(function(err, result) {
        if (err) throw err;
          console.log(result);
    });

    // << db CRUD routes >>

}, function(err) { // failureCallback
    throw (err);
});
...

我们用和来initialize表示数据库dbNamecollectionNamesuccessCallback

内部successCallback

  • GET all使用collection.find(),返回一个游标

    • 游标就像一个迭代器,您可以在其中执行nexthasNext()操作
  • 使用异步方法将游标转换为数组toArray(callback)

    • 对于我们的用例来说,返回完整数组比迭代游标更简单。
  • callback成功将游标转换为数组后运行

    • 我们现在记录结果,但你可以想象返回客户端响应的代码在这里

启动服务器

$ npm install
$ npm start

...应该给出:

Server listening at 4000
[MongoDB connection] SUCCESS
[ { _id: 5d7ed8f31c9d4400009c3775,
    id: 'tt0110357',
    name: 'The Lion King',
    genre: 'animation' } ]

耶!成功了!

作品

现在让我们完成所有的 CRUD 路线!

CRUD 路线

以下是我们的路由处理程序的 CRUD 到 MongoDB 操作的概要。

diskdb请注意,函数和官方的语法之间存在相当大的差异MongoClient

CRUD操作 REST 操作 MongoClient 操作
创造 邮政/items dbCollection.insertOne(object, callback)
阅读一篇 得到/items/:id dbCollection.findOne(query callback)
阅读全部 得到/items dbCollection.find(query).toArray(callback)
更新 /items/:id dbCollection.updateOne(query, { $set: obj }, callback)
删除 删除/items/:id dbCollection.deleteOne(query, callback)

所有这些路线都进入<< db CRUD routes >>我们代码中的标记中。

i. 创建 ➕

// server.js
...
// << db CRUD routes >>
server.post("/items", (request, response) => {
    const item = request.body;
    dbCollection.insertOne(item, (error, result) => { // callback of insertOne
        if (error) throw error;
        // return updated list
        dbCollection.find().toArray((_error, _result) => { // callback of find
            if (_error) throw _error;
            response.json(_result);
        });
    });
});
  1. 对于POST /items处理程序,用于insertOne(item, callback)添加电影request.body(由中间件解析body_parser

  2. 在 中callback如果有的话,insertOne抛出。这里没有使用 ( _ 只是一个布尔值,表示插入文档是否成功)。errorresult_id

  3. 使用 获取更新的列表find(),并返回_result作为其 中的响应callback

注意这里有两个类似的回调:外部回调insertOne,以及内部回调find。这就是为什么我(_error, _result)在内部使用 ,以避免名称冲突。不过你可以随意重命名它们 😉

测试:

$ curl -X POST -H "Content-Type: application/json" --data '{"id": "tt0109830", "name": "Forrest
Gump", "genre": "drama"}' http://localhost:4000/items

[{"_id":"5de5c9d01c9d440000482ef0","id":"tt0110357","name":"The Lion King","genre":"animation"},{"_id":"5de7009967aec74a90f88d67","id":"tt0109830","name":"Forrest Gump","genre":"drama"}]

ii. 阅读一篇🕵️

server.get("/items/:id", (request, response) => {
    const itemId = request.params.id;

    dbCollection.findOne({ id: itemId }, (error, result) => {
        if (error) throw error;
        // return item
        response.json(result);
    });
});
  1. id直接从参数获取(1234例如http://localhost/items/1234)。

  2. id使用查找具有该项的项findOne(query)

query只是一个对象,因此您可以使用键值对进行查询。我们将此查询对象用于finddelete其他 MongoDB 命令。

// query can be:

{ id: 1 }; // find using id

{ name: "The Lion King" }; // find using name

{ id: 1, name: "The Lion King", genre: "action" }; // find using id, name and genre
  1. 退回物品response

测试:

$ curl http://localhost:4000/items/tt0109830

{"_id":"5de7009967aec74a90f88d67","id":"tt0109830","name":"Forrest Gump","genre":"drama"}

iii. 阅读全部🕵️

server.get("/items", (request, response) => {
    // return updated list
    dbCollection.find().toArray((error, result) => {
        if (error) throw error;
        response.json(result);
    });
});

在响应中返回集合中的所有项目,与POST /items中相同

测试:

$ curl http://localhost:4000/items

[{"_id":"5de5c9d01c9d440000482ef0","id":"tt0110357","name":"The Lion King","genre":"animation"},{"_id":"5de7009967aec74a90f88d67","id":"tt0109830","name":"Forrest Gump","genre":"drama"}]

iv. 更新✏️

server.put("/items/:id", (request, response) => {
    const itemId = request.params.id;
    const item = request.body;
    console.log("Editing item: ", itemId, " to be ", item);

    dbCollection.updateOne({ id: itemId }, { $set: item }, (error, result) => {
        if (error) throw error;
        // send back entire updated list, to make sure frontend data is up-to-date
        dbCollection.find().toArray(function(_error, _result) {
            if (_error) throw _error;
            response.json(_result);
        });
    });
});
  1. 获取id来自参数和item来自主体(通过body-parser)。

  2. 使用更新项目id并将其设置为itemdbCollection.updateOne(query, { $set: item }, callback

  • 注意使用 MongoDB 特定的{ $set: item }
  1. 返回更新后的列表,如POST /itemsGET /items

测试:

也许你认为《狮子王》是一部戏剧,因为……好吧,我就不剧透了。🤫 🦁

curl -X PUT -H "Content-Type: application/json" --data '{"genre": "drama"}' http://localhost:4000/items/tt0110357

[{"_id":"5de5c9d01c9d440000482ef0","id":"tt0110357","name":"The Lion King","genre":"drama"},{"_id":"5de7009967aec74a90f88d67","id":"tt0109830","name":"Forrest Gump","genre":"drama"}]

v. 删除 ❌

server.delete("/items/:id", (request, response) => {
    const itemId = request.params.id;
    console.log("Delete item with id: ", itemId);

    dbCollection.deleteOne({ id: itemId }, function(error, result) {
        if (error) throw error;
        // send back entire updated list after successful request
        dbCollection.find().toArray(function(_error, _result) {
            if (_error) throw _error;
            response.json(_result);
        });
    });
});

这里,只id需要来自 params 的,我们将其传递给dbCollection.deleteOne(query)

与以前一样,您可以根据需要轻松地制定查询,因为它只是一个对象。

🤸‍♀️ 挑战:模块化,dbCollection.find()因为我们在 3 个地方使用它。

测试:

$ curl -X DELETE http://localhost:4000/items/tt0109830

[{"_id":"5de5c9d01c9d440000482ef0","id":"tt0110357","name":"The Lion King","genre":"drama"}]

笔记

  1. 回调?!!,为什么用这个而不是 ES6 Promises,或者 ES7 async/await...
  • MongoClient.connect仅支持回调,但我们将在下一课中对这些回调进行 promisify(以及aysnc-await-ify),因为说实话,它们看起来有点像回调地狱。请参阅这篇文章,了解有关回调地狱的有趣概述
  1. 为什么我们会返回响应创建、更新、删除中的所有项目?
  • 关于在更改后如何同步 UI 和后端,有很多选项,这本身就是一个软件架构主题。
  • 在这里,我们只是在创建、更新和删除操作后将更新的项目返回到 UI。我们让前端(例如 React、Vue、Angular、Vanilla JS)根据这些信息更新其状态和视图。

这是完整的代码

https://github.com/lenmorld/devto_posts/tree/master/quick_node_express_mongodb

黑客人

“好的,这很好。但是我能用它做什么呢?”

✅ 提供 HTML 文件
✅ REST API✅
云数据库持久化

现在,这是一个用于小型项目的实际服务器。添加更多路由,并通过 API 请求将一些数据存储到数据库中。只需添加前端即可!™

接下来:

(进行中)

  • MongoDB 回调 Promises 和 Async/Await

本文是我正在撰写的 Node+Express 系列文章的一部分。

与此同时,如果您对 Node+Express 🤓 还不够了解,
请查看我的 Node 研讨会(Gihub repo 和幻灯片):

GitHub 徽标 lenmorld / node_workshop

使用 Node、Express 和 MongoDB 为您的下一个 Web 应用程序构建服务器和 API

节点研讨会

参加研讨会:

$ git checkout dev
$ node server.js

到开发最新版本

$ git checkout master
$ npm start

在根目录下创建一个 .env 文件

NODE_ENV=development
PORT=4000
MONGO_DB_CONNECTION_STRING=YOUR_CONNECTION_STRING_HERE
# API keys go here





我们在这里讨论了:
  • 使用 Node 和 Express
  • 路由、请求和响应
  • 构建 REST API
  • 服务器呈现的模板
  • 连接到 NoSQL(mongo)数据库
  • 使用外部 API,例如 Spotify
  • 以及更多!

祝大家服务愉快!🤓


聊了这么多蒙哥马利,我饿了。
我要去吃我最喜欢的“Hopia Mongo”(一种菲律宾豆馅糕点)🌱。

霍皮亚·蒙戈

图片来自 FoxyFolksy 的文章“Hopia 食谱 - Munggo 和 Ube 馅料” 来源: https: //www.foxyfolksy.com/hopia-recipe-munggo-ube-filling/

文章来源:https://dev.to/lennythedev/rest-api-with-mongodb-atlas-cloud-node-and-express-in-10-minutes-2ii1
PREV
GraphQL 初学者指南
NEXT
CSS 高度全页 CSS 陷阱:如何使用 div 填充页面?