Node.js与MongoDB构建后端评论系统实战指南
作者:永远的12
简介:本文介绍了一个使用Node.js和MongoDB构建的后端评论系统项目。Node.js,一个基于Chrome V8引擎的JavaScript运行环境,采用非阻塞I/O和事件驱动模型,非常适合处理并发连接。MongoDB是一种NoSQL数据库,擅长存储非结构化数据,比如Web API中的JSON格式数据。项目中运用了Express框架进行路由处理和中间件应用,通过Mongoose库简化MongoDB数据库操作。同时,详细讲述了CRUD操作、RESTful API设计、安全性措施、错误处理和测试实践,以确保系统的稳定性和安全性。
1. Node.js后端开发基础
Node.js作为一门基于Chrome V8引擎的JavaScript运行环境,它的非阻塞I/O模型和事件驱动架构使得它在处理大量并发连接方面表现优异,成为了构建网络应用的流行选择。Node.js核心模块涵盖了文件系统、HTTP客户端和服务器、进程管理等,为后端开发提供了强大的基础设施。
1.1 Node.js的安装与环境配置
安装Node.js相对简单,只需访问 Node.js官网 下载对应系统的安装包,按照提示完成安装即可。安装完成后,通过命令行检查Node.js版本,确认安装成功。
node -v
1.2 Node.js基础语法介绍
Node.js使用JavaScript作为编程语言,因此熟悉前端开发的读者可以快速上手。除了ES6+的新特性,Node.js还引入了 require
或 import
模块导入方式,以及提供全局对象 global
和模块作用域 module.exports
的定义方式。
一个简单的"Hello World"程序如下:
console.log('Hello World');
通过这些基础的知识点,我们为后续章节更深层次的Node.js后端开发和架构设计打下了坚实的基础。随着章节的推进,我们将探讨Node.js在构建RESTful API、数据库交互等高级功能中的具体应用。
2. Express框架的应用
Express是一个灵活且功能强大的Node.js web应用框架,提供了多种构建单页、多页和混合Web应用程序的工具。本章将深入探讨Express的核心概念、路由设计、中间件的运用,以及如何处理高级功能如CORS和错误处理。
2.1 Express框架核心概念
2.1.1 路由的设计与实现
路由是任何Web应用程序的基石,它定义了应用程序如何响应客户端请求。在Express中,路由可以基于HTTP请求的方法类型(GET、POST、PUT、DELETE等)和请求的URL路径。
下面是一个简单的Express路由示例,它定义了四个路由:
const express = require('express'); const app = express(); // GET请求到根目录 app.get('/', (req, res) => { res.send('欢迎来到首页!'); }); // POST请求到根目录 app.post('/', (req, res) => { res.send('收到POST请求!'); }); // PUT请求到用户信息 app.put('/user', (req, res) => { res.send('更新用户信息!'); }); // DELETE请求到指定用户 app.delete('/user', (req, res) => { res.send('删除用户成功!'); }); const PORT = 3000; app.listen(PORT, () => { console.log(`应用正在监听端口:${PORT}`); });
路由的匹配是按照它们被定义的顺序进行的。当一个请求到达时,Express会从上到下开始匹配,一旦找到匹配项,就会执行对应的回调函数,并停止进一步的匹配。
2.1.2 中间件的作用与实践
中间件是处理HTTP请求的中间环节,可以访问请求和响应对象,还可以终止请求-响应循环。在Express中,中间件可以是函数、一系列函数,甚至是可调用的类实例。
// 一个简单的中间件函数 function logger(req, res, next) { console.log('请求已收到:', req.method, req.url); next(); // 传递给下一个中间件或路由处理器 } // 应用中间件 app.use(logger); // 应用到所有请求 // 或者指定特定路由使用中间件 app.get('/user', logger, (req, res) => { res.send('用户信息请求已处理'); });
中间件广泛应用于日志记录、身份验证、请求解析、错误处理等。它们可以执行任何与请求、响应和应用程序请求处理函数链中的下一个中间件相关的操作。
2.2 Express框架的高级功能
2.2.1 跨域资源共享(CORS)的处理
跨域资源共享(CORS)是一种安全机制,用于限制Web页面或域名下的脚本如何与另一个域下的资源进行交互。当Web应用托管在与API服务器不同的域名下时,CORS变得尤为重要。
Express中处理CORS的一个简单方法是使用 cors
中间件:
const cors = require('cors'); const app = express(); app.use(cors()); // 启用所有域的CORS支持 // 或者更精细的配置 app.use(cors({ origin: 'http://example.com', // 允许来自此域的请求 methods: ['GET', 'POST'], // 允许的HTTP方法 allowedHeaders: ['Content-Type', 'Authorization'], // 允许的HTTP请求头 credentials: true // 允许发送cookie })); // RESTful API路由和处理逻辑 // ...
2.2.2 错误处理与日志记录
错误处理是构建健壮应用的关键部分。Express提供了错误处理中间件来捕获和响应运行时错误。
app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('发生错误!'); }); // 或者,使用自定义错误处理来处理特定类型的错误 app.get('/user', (req, res) => { // 模拟错误 throw new Error('获取用户信息失败!'); }); app.use((err, req, res, next) => { if (err.message === '获取用户信息失败!') { res.status(404).send('用户未找到'); } else { res.status(500).send('服务器错误'); } });
日志记录也是中间件,可以用于记录每个请求的详细信息,便于问题调试和性能监控。Express没有内置的日志记录功能,通常会使用像 morgan
这样的第三方库。
const morgan = require('morgan'); app.use(morgan('dev')); // 使用'dev'格式记录请求
以上是对Express框架核心概念和高级功能的介绍。下一章将探讨MongoDB数据库的操作,以及如何在Node.js项目中有效地使用Mongoose库。
3. MongoDB文档型数据库操作
MongoDB作为NoSQL领域的领导者之一,以其灵活的文档数据模型和高性能、高可用性的特点,赢得了开发者们的青睐。本章节将深入探讨MongoDB的基础操作和一些进阶特性,旨在帮助读者构建和优化以MongoDB为后端存储的应用。
3.1 MongoDB的基本操作
在这一小节中,我们将从数据库和集合的管理开始,进而学习如何进行常用的查询和更新操作。
3.1.1 数据库与集合的管理
MongoDB的数据库和集合可以被动态创建,无需预先定义,极大地方便了开发者的使用。
创建和删除数据库
在MongoDB中,可以通过指定要使用的数据库名来创建一个数据库。如果该数据库不存在,MongoDB会在第一次存入数据时自动创建。
use myDatabase // 切换到myDatabase数据库,如果不存在则创建 // 删除数据库 db.dropDatabase();
上述代码展示了如何使用 use
命令来切换到一个已存在的数据库,或者切换到一个不存在的数据库,MongoDB会自动创建。同时, dropDatabase
命令可以用来删除当前使用的数据库。
创建和删除集合
集合可以看作关系数据库中的表。在MongoDB中,可以创建集合来存储文档。
// 创建集合 db.createCollection("users") // 删除集合 db.users.drop();
createCollection
命令用于创建一个新集合,而 drop
命令则是用来删除一个集合。在实际应用中,集合创建和删除是一个常用操作,尤其是在进行数据模型调整时。
3.1.2 常用查询与更新操作
MongoDB的查询操作十分灵活,支持多种查询条件,并允许进行复杂的查询组合。
查询操作
查询操作支持各种条件表达式,比如:
// 查询所有文档 db.users.find() // 指定查询条件 db.users.find({ age: { $gte: 18 } }) // 排序查询结果 db.users.find().sort({ age: -1 })
在上述代码示例中, find
方法用于返回集合中所有文档。若要添加查询条件,可以传递一个JSON对象,例如查找年龄大于或等于18岁的用户。 sort
方法则用于对返回的结果进行排序。
更新操作
更新操作可以修改已有文档的内容。
// 更新单个文档 db.users.updateOne({ _id: 1 }, { $set: { age: 20 } }) // 更新多个文档 db.users.updateMany({}, { $inc: { age: 1 } })
updateOne
方法用于更新第一个匹配的文档。 $set
操作符用于指定要修改的字段及其新值。 updateMany
方法则是用来更新所有匹配的文档, $inc
操作符用于对现有字段的值进行增加。
3.2 MongoDB的进阶特性
MongoDB不仅提供基本的CRUD操作,还具备一些高级特性,这些特性可以帮助我们更高效地管理数据,提升数据库性能。
3.2.1 索引的创建与优化
索引是提高数据库查询性能的重要手段。MongoDB提供了多种类型的索引。
创建索引
// 创建索引 db.users.createIndex({ username: 1 }, { unique: true })
在上述代码示例中,我们为 users
集合创建了一个基于 username
字段的升序索引,并且通过 unique
参数确保用户名的唯一性。
索引优化
MongoDB的索引不是越多越好,不合理的索引会造成性能问题和额外的存储开销。
- 分析查询模式,确定创建索引的需求。 - 使用`explain("executionStats")`来监控查询性能。 - 定期审查索引,去除未使用的索引。
下面表格概括了索引创建和优化中需要注意的几个关键点:
| 索引特征 | 说明 | |---------|------| | 升序和降序 | 索引可以是升序(1)或降序(-1)。 | | 复合索引 | 可以在多个字段上创建索引。 | | 唯一索引 | 索引字段值必须唯一。 | | 索引覆盖 | 查询可以直接由索引提供,无需访问文档。 | | 索引性能 | 索引可以提高查询性能,但也会增加写操作的负担。 |
3.2.2 复制集与分片的原理和应用
MongoDB通过复制集和分片技术来保证数据的高可用性和可扩展性。
复制集原理
复制集是MongoDB中用于提供数据冗余和高可用性的一种机制。
- 主节点(Primary):处理客户端请求,复制操作日志。 - 从节点(Secondary):复制主节点的操作日志并保持数据的一致性。 - 仲裁节点(Arbiter):不存储数据,只参与投票过程,提高容错性。
复制集保证了当主节点出现故障时,能迅速选举出新的主节点来接管服务,从而最小化了宕机时间。
分片的原理和应用
分片是MongoDB实现横向扩展的一种技术。
// 启用分片 sh.enableSharding("myDatabase") // 分片集合 sh.shardCollection("myDatabase.users", { username: 1 })
分片是通过将数据分散到多个服务器上的不同节点来提高性能和容量的。 enableSharding
方法用于为指定数据库启用分片。 shardCollection
方法则是用于对集合进行分片操作,指定基于哪个字段进行分片。
表格形式总结复制集与分片的关键概念:
| 特征 | 复制集 | 分片 | |------|--------|------| | 目标 | 高可用性 | 数据和负载均衡 | | 组件 | 主节点、从节点、仲裁节点 | 配置服务器、分片、mongos路由 | | 部署 | 快速部署,易于管理 | 需要更多资源,适合大数据量 |
以上就是MongoDB基础操作和进阶特性的一些深入讲解。在实际应用中,掌握这些技能将能帮助开发者更好地构建和优化使用MongoDB的应用程序。
4. Mongoose库在Node.js中的使用
4.1 Mongoose的Schema设计
4.1.1 数据类型与验证规则
在Node.js中使用Mongoose库与MongoDB数据库交互时,数据模型的定义是一个核心环节。Mongoose通过Schema定义了数据的结构和规则。Schema不仅描述了文档的结构,还可以指定文档的验证规则,以确保数据的准确性和一致性。
const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Name is required.'], minLength: [2, 'Name must be at least 2 characters long.'] }, age: { type: Number, min: [0, 'Age must be a positive number.'], max: [150, 'Age must be less than 150.'] }, email: { type: String, match: [/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, 'Invalid email format'] } }); const User = mongoose.model('User', userSchema); const user = new User({ name: 'John', age: -1, email: 'john.doe' }); user.save().then(doc => { console.log('User created:', doc); }).catch(err => { console.error('Error saving user:', err.message); });
在上述示例代码中,定义了一个用户模型Schema。其中包含 name
, age
, 和 email
三个字段,每个字段都规定了数据类型和验证规则:
name
字段类型为String
,必填项且长度不得小于2个字符。age
字段类型为Number
,设置了最小值为0,最大值为150,超出范围将导致验证失败。email
字段类型为String
,使用正则表达式进行格式校验。
代码执行时,如果不符合验证规则,将不会保存到数据库,并且会抛出错误提示信息。Mongoose通过这些内置验证规则,帮助开发者在数据保存到数据库之前,保证数据的有效性和格式的正确性。
4.1.2 钩子函数的作用与应用
在Mongoose中,Schema还提供了钩子(Hooks)功能,即在数据模型的生命周期的不同阶段自动执行的函数。这包括文档的创建、保存、更新和删除等操作前后。使用钩子可以在不修改业务逻辑代码的情况下,轻松地添加诸如日志记录、权限检查、数据验证等预处理逻辑。
userSchema.pre('save', function(next) { console.log('Before saving document'); // Additional logic before saving the document next(); }); userSchema.post('save', function(doc) { console.log('After saving document'); // Additional logic after the document is saved });
在上面的代码中, pre
和 post
分别指定了保存操作之前的预处理和保存操作之后的后续处理函数。在 pre
钩子函数中,可以在数据真正保存到数据库之前插入额外的逻辑。例如,可以在保存前检查某些字段是否符合特定的条件,或者修改某些字段的值。
使用钩子函数可以让代码更加清晰和易于维护,同时保持业务逻辑代码的纯净性。
4.2 Mongoose的模型操作
4.2.1 CRUD操作的封装与优化
CRUD操作是后端开发中最为基础的操作,即创建(Create)、读取(Read)、更新(Update)、删除(Delete)数据。在Mongoose中,可以非常方便地对MongoDB进行CRUD操作,它提供了简单直观的API来处理这些操作。
// Create operation const newUser = new User({ name: 'Alice', age: 30, email: 'alice@example.com' }); newUser.save().then(doc => { console.log('New user created:', doc); }).catch(err => { console.error('Error creating user:', err.message); }); // Read operation User.find({}).then(users => { console.log('Users found:', users); }).catch(err => { console.error('Error fetching users:', err.message); }); // Update operation User.findByIdAndUpdate( newUser._id, { $set: { age: 31 } }, { new: true } ).then(updatedUser => { console.log('User updated:', updatedUser); }).catch(err => { console.error('Error updating user:', err.message); }); // Delete operation User.findByIdAndRemove(newUser._id).then(deletedUser => { console.log('User deleted:', deletedUser); }).catch(err => { console.error('Error deleting user:', err.message); });
在上述代码中,展示了如何使用Mongoose进行基础的CRUD操作。每个操作方法都有对应的链式调用,支持回调函数或Promise的形式返回结果。使用Promise可以在异步操作中使用 .then()
和 .catch()
来处理结果和错误。
封装CRUD操作可以提高代码的复用性,并且有助于维持代码的组织性和可读性。合理优化CRUD操作不仅能提升应用程序的性能,还能保证数据操作的安全性。
4.2.2 高级查询技巧
Mongoose除了提供基本的CRUD操作外,还允许执行更为复杂的查询操作。例如,可以使用MongoDB的查询操作符来实现条件查询,并且可以对结果进行排序、限制数量以及跳过某些结果。
// Advanced querying with operators and conditions User.find({ age: { $gte: 25, $lte: 35 } }) .sort({ name: 1 }) .limit(10) .skip(5) .then(users => { console.log('Users between 25 and 35, sorted, limited, and skipped:', users); }) .catch(err => { console.error('Error querying users:', err.message); });
在上面的代码中, find
方法使用了 $gte
和 $lte
操作符来指定查询条件,表示查找年龄在25到35岁之间的用户。 sort
方法根据 name
字段进行升序排列, limit
和 skip
方法用于限制返回的文档数量和跳过一定的文档数量。
高级查询技巧可以帮助开发者从数据库中获取更加精准和复杂的数据集,有助于提高应用的灵活性和用户体验。
请注意,实际编写代码时,应当根据实际项目需求进行优化和调整。上述代码仅供参考和学习使用。在真实的生产环境中,可能还需要考虑更多的异常处理、日志记录、性能优化等因素。
5. CRUD操作实现与应用
5.1 基于Mongoose的CRUD实现
5.1.1 创建与读取数据的接口
实现基于Mongoose的创建(Create)和读取(Read)操作,是任何数据交互场景的基础。我们首先创建一个简单的数据模型,然后通过编写接口来处理这些操作。
在Mongoose中,我们首先需要定义一个Schema,然后基于这个Schema来创建一个模型(Model)。以下是一个简单的用户(User)数据模型的定义:
const mongoose = require('mongoose'); const { Schema } = mongoose; const userSchema = new Schema({ username: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true }, password: { type: String, required: true }, createdAt: { type: Date, default: Date.now } }); const User = mongoose.model('User', userSchema); module.exports = User;
然后,我们创建两个接口来处理创建和读取操作。首先是创建用户的接口:
router.post('/users', async (req, res) => { try { const newUser = new User(req.body); await newUser.save(); res.status(201).send({ message: 'User created successfully.', userId: newUser._id }); } catch (error) { res.status(500).send({ message: 'Error creating user.' }); } });
读取操作可以通过查询用户集合来实现,例如获取所有用户:
router.get('/users', async (req, res) => { try { const users = await User.find(); res.status(200).send(users); } catch (error) { res.status(500).send({ message: 'Error fetching users.' }); } });
5.1.2 更新与删除数据的逻辑
对于更新和删除操作,Mongoose也提供了相应的方法来完成。更新操作可以通过Model的 updateOne
方法来实现,而删除操作可以使用 deleteOne
方法。
更新用户信息的接口可以如下编写:
router.put('/users/:id', async (req, res) => { try { const updatedUser = await User.findByIdAndUpdate(req.params.id, req.body, { new: true }); if (!updatedUser) { return res.status(404).send({ message: 'User not found.' }); } res.send(updatedUser); } catch (error) { res.status(500).send({ message: 'Error updating user.' }); } });
删除用户的接口示例如下:
router.delete('/users/:id', async (req, res) => { try { const user = await User.findByIdAndDelete(req.params.id); if (!user) { return res.status(404).send({ message: 'User not found.' }); } res.send({ message: 'User deleted successfully.' }); } catch (error) { res.status(500).send({ message: 'Error deleting user.' }); } });
这些CRUD操作是构建任何后端系统数据交互层的基础,并且可以进一步扩展,比如增加验证逻辑、事务处理、权限检查等。
5.2 CRUD操作的应用案例
5.2.1 实际项目中的数据交互
在实际的项目中,CRUD操作是数据交互的基石。以一个典型的博客系统为例,用户可以创建文章、查看文章列表、编辑文章以及删除文章。这些操作在后端逻辑中都体现为CRUD操作。
比如,一个文章(Post)的数据模型可能如下:
const postSchema = new Schema({ title: { type: String, required: true }, content: { type: String, required: true }, author: { type: Schema.Types.ObjectId, ref: 'User', required: true }, publishedAt: { type: Date, default: Date.now } }); const Post = mongoose.model('Post', postSchema); module.exports = Post;
在这个基础上,我们可以实现文章的CRUD接口,允许用户发布新文章、编辑、发布文章等。
5.2.2 前后端分离下的数据交互
在现代Web开发中,前后端分离是常见的架构模式。在这种模式下,后端通常通过RESTful API来暴露CRUD操作给前端。
以一个用户登录功能为例,前端会通过发送HTTP请求到后端的登录接口来验证用户的凭据。后端接收到请求后,会通过CRUD操作来查询用户信息、验证密码等。
例如,登录接口可能如下实现:
router.post('/login', async (req, res) => { try { const user = await User.findOne({ username: req.body.username }); if (user && await bcrypt.compare(req.body.password, user.password)) { const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' }); res.status(200).send({ auth: true, token: token }); } else { res.status(401).send({ auth: false, message: 'Authentication failed.' }); } } catch (error) { res.status(500).send({ message: 'Error during authentication.' }); } });
这个示例不仅展示了如何在前后端分离架构下使用CRUD操作,还涉及了密码哈希验证和JWT(JSON Web Tokens)的使用,这些都是现代Web应用中常用的技术。
在设计这样的接口时,我们需要考虑到安全性问题,比如使用HTTPS来加密传输的数据,对敏感信息进行加密存储,以及对输入进行严格的验证和清理以防止SQL注入等安全漏洞。此外,对于API的响应,合理的HTTP状态码的使用也是不可忽视的,比如使用 200 OK
表示操作成功,使用 201 Created
表示资源被成功创建,以及使用 400 Bad Request
和 401 Unauthorized
等来处理错误情况。
在下一章节中,我们将探讨RESTful API的设计原则,以及如何合理地运用HTTP状态码来提升API设计的质量。
6. RESTful API设计和状态码应用
6.1 RESTful API设计原则
RESTful API是当今Web服务架构中被广泛采用的一种风格。它基于REST(Representational State Transfer)原则,强调轻量级、无状态和可访问性。在设计RESTful API时,重要的是要理解资源的概念,以及如何以统一的方式表示和操作这些资源。
6.1.1 资源的表示与操作
在RESTful架构中,所有事物都可以被视为资源。例如,一篇文章、一个用户或一个订单都可以是一个资源。每个资源都应该有一个唯一的URI(Uniform Resource Identifier),通过这个URI可以获取、创建、修改或删除资源。
在设计API时,需要遵循一致性原则,即URI应该清晰地表示出它们所指向的资源,而操作这些资源的方法则通过HTTP动词来区分,如GET(读取资源)、POST(创建资源)、PUT/PATCH(更新资源)、DELETE(删除资源)。
例如,以下是一些标准的RESTful API设计实践:
GET /articles # 获取文章列表 GET /articles/:id # 获取指定ID的文章 POST /articles # 创建新文章 PUT /articles/:id # 更新指定ID的文章 PATCH /articles/:id # 部分更新指定ID的文章 DELETE /articles/:id # 删除指定ID的文章
6.1.2 API版本控制的最佳实践
随着应用程序的发展,API可能需要更新和迭代。API版本控制允许开发者在不影响现有客户端的情况下发布新的API功能。通常有两种常见的方法进行版本控制:
- URL路径版本控制,如
/v1/articles
或/v2/articles
。 - 请求头版本控制,通过在请求头中添加
Accept-version
或类似字段指定API版本。
选择哪种方法取决于项目需求和个人偏好。然而,使用URL路径进行版本控制是最常见的做法,因为它简单明了,易于实现。
GET /v1/articles # 获取旧版本的文章列表 GET /v2/articles # 获取新版本的文章列表
6.2 状态码的合理运用
HTTP状态码是服务器响应客户端请求时返回的数字代码。状态码可以告诉客户端请求是否成功,或者在发生错误时指示错误的性质。
6.2.1 HTTP状态码的分类与意义
HTTP状态码可以分为五个类别:
- 1xx(信息性状态码):接收的请求正在处理。
- 2xx(成功状态码):请求正常处理完毕。
- 3xx(重定向状态码):需要后续操作才能完成这一请求。
- 4xx(客户端错误状态码):服务器无法处理请求。
- 5xx(服务器错误状态码):服务器处理请求出错。
例如,200 OK表示请求成功,404 Not Found表示请求的资源不存在,500 Internal Server Error表示服务器内部错误。
6.2.2 状态码在API设计中的应用
在设计RESTful API时,合理地使用HTTP状态码能够提高API的可读性和可维护性。例如,成功的CRUD操作应该返回合适的2xx状态码,如200 OK或201 Created。如果请求有语法错误,应该返回400 Bad Request。如果是认证失败,应返回401 Unauthorized。
下面是一个简单的状态码应用示例:
GET /articles/123 HTTP/1.1 200 OK Content-Type: application/json { "id": "123", "title": "Understanding RESTful API", "content": "..." } POST /articles HTTP/1.1 201 Created Content-Type: application/json { "id": "456", "title": "Designing RESTful APIs", "content": "..." } DELETE /articles/123 HTTP/1.1 204 No Content
通过合理使用和理解HTTP状态码,开发者可以更有效地与API进行交互,同时提升整体的用户体验和系统的健壮性。
到此这篇关于Node.js与MongoDB构建后端评论系统实战的文章就介绍到这了,更多相关Node.js与MongoDB评论系统内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- Node.js使用MongoDB的ObjectId作为查询条件的方法
- node.js将MongoDB数据同步到MySQL的步骤
- node.js利用mongoose获取mongodb数据的格式化问题详解
- Node.js+jade+mongodb+mongoose实现爬虫分离入库与生成静态文件的方法
- 利用node.js+mongodb如何搭建一个简单登录注册的功能详解
- node.js连接MongoDB数据库的2种方法教程
- 利用Vue.js+Node.js+MongoDB实现一个博客系统(附源码)
- 从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
- Node.js和MongoDB实现简单日志分析系统
- node.js连接mongoDB数据库 快速搭建自己的web服务