节点研讨会
参加研讨会:
$ 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
这次,让我们把数据搬到云端吧!💾 ☁。还有什么比免费的云数据库
更好的方法呢? 我们将使用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 屏幕截图可能会有细微的差异,但所描述的步骤应该可以让您获得相同的结果。
https://www.mongodb.com/cloud/atlas/register
免费的Starter Cluster M0配备 512 MB 存储空间、共享 RAM 和 vCPU。
对于我们的启动 Node 项目来说这应该足够了。
您可以将其余部分保留为免费默认值。
创建集群。
创建和配置可能需要几分钟
在我们刚刚创建的集群中点击[连接]。
出现的对话框提供以下选项:
白名单意味着只允许选定的(因此受信任的)实体访问
[添加您当前的 IP 地址],它会自动获取您当前的公共 IP 地址。您也可以选择添加描述,例如“我的家庭 IP 地址”。
ipconfig
或者ifconfig
可能只会给您内部网络地址。0.0.0.0/0
启用所有 IP 地址,这简化了此过程,但却使其非常不安全。输入你的用户名和密码。这将是第一个管理员(“root”)用户,然后[创建 MongoDB 用户](https://mongodb.io/users/)。
请保留这些凭证,因为我们稍后会使用它们。
关闭窗口。我们稍后会连接到集群。
从集群视图中,单击 [集合],然后单击 [添加我自己的数据]
data
movies
🎥 本系列电影来自 IMDB。您可以使用
id
任何电影页面网址。例如,在“狮子王”页面中https://www.imdb.com/title/tt0110357
;id
是tt0110357
。
插入文档
_id
像以前一样插入电影条目 - 保留Atlas 提供的内容,因为这是内部的完美!现在我们拿到数据了。是时候连接集群了。
返回到集群视图,然后单击我们的集群中的连接。
选择[连接您的应用程序]
保留默认的 Node.js 版本 3+
复制连接字符串。我们将在下一步中使用它。
现在我们准备深入研究代码了!
https://github.com/lenmorld/devto_posts/tree/master/quick_node_express_diskdb
mongodb
驱动程序$ npm install mongodb
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
};
MongoClient
。successCallback
传递对象dbCollection
。
failureCallback
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
方法),并为数据库的信息定义变量。
// 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
表示数据库。dbName
collectionName
successCallback
内部successCallback
:
GET all
使用collection.find()
,返回一个游标。
next
等hasNext()
操作使用异步方法将游标转换为数组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 到 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 >>
我们代码中的标记中。
// 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);
});
});
});
对于POST /items
处理程序,用于insertOne(item, callback)
添加电影request.body
(由中间件解析body_parser
)
在 中callback
,如果有的话,insertOne
抛出。这里没有使用 ( _ 只是一个布尔值,表示插入文档是否成功)。error
result
_id
使用 获取更新的列表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"}]
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);
});
});
id
直接从参数获取(1234
例如http://localhost/items/1234)。
id
使用查找具有该项的项findOne(query)
。
query
只是一个对象,因此您可以使用键值对进行查询。我们将此查询对象用于find
和delete
其他 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
response
测试:
$ curl http://localhost:4000/items/tt0109830
{"_id":"5de7009967aec74a90f88d67","id":"tt0109830","name":"Forrest Gump","genre":"drama"}
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"}]
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);
});
});
});
获取id
来自参数和item
来自主体(通过body-parser
)。
使用更新项目id
并将其设置为。item
dbCollection.updateOne(query, { $set: item }, callback
{ $set: item }
POST /items
和GET /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"}]
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"}]
MongoClient.connect
仅支持回调,但我们将在下一课中对这些回调进行 promisify(以及aysnc-await-ify),因为说实话,它们看起来有点像回调地狱。请参阅这篇文章,了解有关回调地狱的有趣概述。https://github.com/lenmorld/devto_posts/tree/master/quick_node_express_mongodb
✅ 提供 HTML 文件
✅ REST API✅
云数据库持久化
现在,这是一个用于小型项目的实际服务器。添加更多路由,并通过 API 请求将一些数据存储到数据库中。只需添加前端即可!™
(进行中)
本文是我正在撰写的 Node+Express 系列文章的一部分。
与此同时,如果您对 Node+Express 🤓 还不够了解,
请查看我的 Node 研讨会(Gihub repo 和幻灯片):
$ git checkout dev
$ node server.js
$ git checkout master
$ npm start
NODE_ENV=development
PORT=4000
MONGO_DB_CONNECTION_STRING=YOUR_CONNECTION_STRING_HERE
# API keys go here
祝大家服务愉快!🤓
聊了这么多蒙哥马利,我饿了。
我要去吃我最喜欢的“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