node.js操作数据库之MongoDB+mongoose篇
<h1 id="前言">前言</h1><blockquote>
<p><code>node.js</code>的出现,使得用前端语法(javascript)开发后台服务成为可能,越来越多的前端因此因此接触后端,甚至转向全栈发展。后端开发少不了数据库的操作。<code>MongoDB</code>是一个基于分布式文件存储的开源数据库系统。本文为大家详细介绍了如何用<code>node.js</code> + <code>mongoose</code> 玩转<code>MongoDB</code>。希望能帮到有需要的人。</p>
</blockquote>
<blockquote>
<p>由于我用Mac开发,以下所有操作都是在Mac下进行。</p>
</blockquote>
<h1 id="一-环境搭建">一、 环境搭建</h1>
<h2 id="安装nodejs">安装Node.js</h2>
<blockquote>
<p>有 node 环境的可以跳过。</p>
</blockquote>
<p>nodejs官网提供了 macOS 安装包,直接下载安装即可。现在 nodejs 稳定版已经到了<code>12.11.1</code> 。</p>
<h2 id="安装mongodb">安装MongoDB</h2>
<p>MongoDB 是为现代应用程序开发人员和云时代构建的基于文档的通用分布式数据库。</p>
<blockquote>
<p>上个月(9月) macOS 包管理器 Homebrew 宣布移除 MongoDB 。原因是去年10月 MongoDB 宣布将其开源许可证从 <code>GNU AGPLv3</code> 切换到 <code>SSPL(Server Side Public License)</code>,以此回应 AWS 等云厂商将 MongoDB 以服务的形式提供给用户而没有回馈社区的行为,MongoDB 希望从软件即服务上获取收入。Homebrew 认为 MongoDB 已经不再属于开源范畴...</p>
</blockquote>
<p>言归正传,由于上述原因,我们不能直接使用<code>brew install mongodb</code>来安装 MongoDB 了。好在 MongoDB 自己维护了一个定制化的 Homebrew tap。并在 Install MongoDB Community Edition<br>
更新了安装步骤。</p>
<p>Mac下 MongoDB 的最新安装步骤如下:</p>
<h4 id="1-首先安装-homebrew">1. 首先安装 Homebrew</h4>
<p>Homebrew 是 macOS 的包管理器。因为 OSX 默认不包含 Homebrew brew 包,所以要先安装,已经安装过的可以跳过。</p>
<pre><code>/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
</code></pre>
<p>安装过程会有点长,终端输出信息超过一屏,这里我只截取了头尾两部分。<br>
<img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f33d76e9338?w=2016&h=640&f=jpeg&s=206835"></p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f3aaf547b88?w=2012&h=730&f=jpeg&s=340512"></p>
<h4 id="2-然后获取下-mongodb-homebrew-tap">2. 然后获取下 MongoDB Homebrew Tap</h4>
<pre><code>brew tap mongodb/brew
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f4385b78966?w=2016&h=424&f=jpeg&s=158392"></p>
<h4 id="3-最后安装-mongodb-ce社区版">3. 最后安装 MongoDB CE(社区版)</h4>
<pre><code>brew install mongodb-community@4.2
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f4c50145649?w=2018&h=362&f=jpeg&s=212165"></p>
<p>现在你的 Mac 上就已经安装好 MongoDB 环境了。</p>
<h2 id="安装mongoose">安装mongoose</h2>
<blockquote>
<p>node.js 是可以直接操作 MongoDB 的,但是通过 MongoDB 命令语法直接编写 MongoDB 验证、数据类型转换和业务逻辑模版比较繁琐。所以我们使用了 mongoose。</p>
</blockquote>
<p>mongoose 是 MongoDB 的一个对象模型工具,它对 MongoDB 的常用方法进行了封装,让 node.js 操作 MongoDB 更加优雅简洁。</p>
<p>刚才的 node.js 和 MongoDB 都是安装在全局环境,mongoose 则是安装在你的项目下:</p>
<pre><code>cd your-project
npm i -S mongoose
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f550615daca?w=2014&h=226&f=jpeg&s=94470"></p>
<p>现在,你的开发环境就已经全部安装好了。</p>
<h1 id="二启动mongodb服务">二、启动MongoDB服务</h1>
<p>要操作 MongoDB ,首先要启动它。<br>
有两种方式启动 MongoDB 服务:</p>
<h4 id="1-在前台运行">1. 在前台运行</h4>
<pre><code>mongod --config /usr/local/etc/mongod.conf
</code></pre>
<p>前台运行的好处就是,可以查看一些反馈和日志,便于调试。另外如果要关闭服务,只需要在终端按 <code>control + c</code> 键即可。<br>
<img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f5d720dd67e?w=1282&h=76&f=jpeg&s=26063"></p>
<h4 id="2-也可以作为-macos-服务在后台运行">2. 也可以作为 macOS 服务,在后台运行</h4>
<pre><code>brew services start mongodb-community@4.2
</code></pre>
<p>好处是开机就自动启动,随时可以使用。<br>
<img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f6448182492?w=2018&h=280&f=jpeg&s=146496"><br>
这种启动方式,如果要关闭服务,可以通过 <code>stop</code> 命令:</p>
<pre><code>brew services stop mongodb-community@4.2
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f6bb66430c9?w=2022&h=86&f=jpeg&s=61162"></p>
<p>现在,你的 MongoDB 数据库已经开启了。</p>
<h1 id="三操作mongodb">三、操作MongoDB</h1>
<p>操作之前先解释一下MongoDB和mongoose里的一些核心概念。</p>
<p><strong>MongoDB</strong></p>
<ul>
<li>MongoDB 中的数据记录是一种 <code>BSON</code> 格式的文件(BSON是一种用二进制描述的JSON文件格式)。</li>
<li>MongoDB 将<code>文件</code>存储在<code>集合</code>中,将<code>集合</code>存储在<code>数据库</code>中。</li>
<li>MongoDB 的数据库、集合都不用手动创建。</li>
<li><code>集合collection</code>: 相当于关系型数据库中的<code>表table</code>。</li>
<li><code>文件document</code>: MongoDB 的数据记录单位,相当于关系型数据库中的<code>记录row</code>。</li>
</ul>
<p><strong>mongoose</strong></p>
<ul>
<li><code>schema</code>: 在 mongoose 中,所有的东西都来源于一个 <code>schema</code>,每个<code>schema</code> 映射了一个 MongoDB 的<code>集合</code>,它定义了这个<code>集合</code>中的<code>文档</code>的骨架。</li>
<li><code>model</code>: 一个<code>文件</code>的构造器,通过编译<code>schema</code>得到,一个<code>model</code>的实例就是一个<code>文件</code>,<code>model</code>负责从 MongoDB 数据库中创建和读取<code>文档</code>。</li>
</ul>
<p>更多mongoose概念可以在mongoose guide中查阅。</p>
<p>数据库操作:</p>
<h2 id="1-使用-mongoose-连接-mongodb">1. 使用 mongoose 连接 MongoDB</h2>
<p>在项目中创建 <code>connection.js</code> 文件</p>
<pre><code>// connection.js file
const mongoose = require('mongoose');
const conn = mongoose.createConnection(
// 连接地址,MongoDB 的服务端口为27017
// dbtest是我要使用的数据库名,当往其中写数据时,MongoDB 会自动创建一个名为dbtest的数据库,不用事先手动创建。
'mongodb://127.0.0.1:27017/dbtest',
// 一些兼容配置,必须加,你不写运行的时候会提示你加。
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
conn.on('open', () => {
console.log('打开 mongodb 连接');
})
conn.on('err', (err) => {
console.log('err:' + err);
})
</code></pre>
<p>运行:</p>
<pre><code>node conection.js
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f75c0b353ed?w=1522&h=92&f=jpeg&s=24572"></p>
<p>可以看到打印出“打开 mongodb 连接”,并且运行一直在等待。</p>
<p>这说明现在已经成功连接上 MongoDB 了,接下来可以开始操作数据库了。</p>
<p>为了方便扩展起见,我们先对 <code>connection.js</code> 改造一下,让它作为模块导出,这样就可以在其他地方导入复用了。</p>
<pre><code>// connection.js file
const mongoose = require('mongoose');
const conn = mongoose.createConnection(
'mongodb://127.0.0.1:27017/dbtest',
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
conn.on('open', () => {
console.log('打开 mongodb 连接');
})
conn.on('err', (err) => {
console.log('err:' + err);
})
module.exports = conn; //commonJs 语法,导出conn模块。
</code></pre>
<h2 id="2-添加操作">2. 添加操作</h2>
<blockquote>
<p><code>save | create</code> 方法</p>
</blockquote>
<p>新建<code>insert.js</code>文件</p>
<pre><code>// insert.js file
let mongoose = require('mongoose');
// 导入连接模块
let connection = require('./connection');
// 创建schema
let StudentSchema = new mongoose.Schema({
name: String,
age: Number
})
// 通过connection和schema创建model
let StudentModel = connection.model('Student', StudentSchema);
// 通过实例化model创建文档
let studentDoc = new StudentModel({
name: 'zhangsan',
age: 20
})
// 将文档插入到数据库,save方法返回一个Promise对象。
studentDoc.save().then((doc) => {
console.log(doc)
})
</code></pre>
<p>运行:</p>
<pre><code>node insert.js
</code></pre>
<p>为了更直观看到操作数据库的结果,推荐大家安装一个数据库可视化工具:Robo3T,下载mac版安装即可。</p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f93aafab340?w=3104&h=1872&f=jpeg&s=435949"></p>
<p>点击 Robo3T 左上角连接我们的数据库后,可以看到 MongoDB 自动帮我们生成了数据库和集合,并且已经插入了一条记录:</p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0f8da61d5bc3?w=2816&h=1708&f=jpeg&s=399760"></p>
<p>或者还可以直接通过Model的create方法直接插入数据,返回的也是一个Promise:</p>
<pre><code>StudentModel.create({
name: 'lisi',
age: 19
}).then((doc) => {
console.log(doc)
})
</code></pre>
<h2 id="3-读取操作">3. 读取操作</h2>
<blockquote>
<p><code>find</code> 方法<br>
为更加合理复用代码,我们先把 StudentSchema 和 StudentModel 抽离出来:</p>
</blockquote>
<p>新建<code>StudentSchema.js</code>翁建</p>
<pre><code>// StudentSchema.js file
const mongoose = require('mongoose');
let StudentSchema = mongoose.Schema({
name: String,
age: Number
})
module.exports = StudentSchema;
</code></pre>
<p>新建<code>StudentModel.js</code>文件</p>
<pre><code>// StudentModel.js file
const connection = require('./connection');
const StudentSchema = require('./StudentSchema');
let StudentModel = connection.model('Student', StudentSchema);
module.exports = StudentModel;
</code></pre>
<p>然后新建<code>query.js</code>文件</p>
<pre><code>// query.js file
const StudentModel = require('./StudentModel');
// 富查询条件,对象格式,键值对,下面为查询 name 为 lisi 的记录
StudentModel.find({name: 'lisi'}).then(doc => {
console.log(doc);
})
</code></pre>
<p>运行</p>
<pre><code>node query.js
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0fa299050daa?w=1138&h=86&f=jpeg&s=38695"></p>
<p>可以看到<code>name</code>为<code>lisi</code>的记录被打印了出来。</p>
<p>如果想查询整个集合:</p>
<pre><code>// 不放查询条件即查询所有的记录
StudentModel.find({}).then(doc => {
console.log(doc);
})
</code></pre>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0fa6fa31e327?w=1156&h=266&f=jpeg&s=78778"></p>
<p>可以看到集合中的所有记录被打印了出来。</p>
<h2 id="4-更新操作">4. 更新操作</h2>
<blockquote>
<p><code>update|updateOne|updateMany</code> 方法</p>
</blockquote>
<p>新建<code>update.js</code>文件</p>
<pre><code>// update.js file
const StudentModel = require('./StudentModel');
// update 方法接收2个参数,第一个是查询条件,第二个是修改的值
// 下面把name为lisi的记录,将他的age修改为80
StudentModel.update({name: 'lisi'}, {age: 80}).then(result => {
console.log(result)
})
</code></pre>
<p>进入 Robo3T,可以看到数据被更改,切换到表格模式更加直观:</p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0facbe52b8b3?w=2078&h=438&f=jpeg&s=151772"></p>
<p>不过在终端,提示<code>DeprecationWarning: collection.update is deprecated. Use updateOne, updateMany, or bulkWrite instead.</code></p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0fb06d42f602?w=1552&h=182&f=jpeg&s=60606"></p>
<p>意思是建议我们使用 <code>updateOne</code>、<code>updateMany</code>或者<code>bulkWrite</code></p>
<ul>
<li>update 更新查询到的所有结果,方法已经不提倡使用,已被updateMany替代。</li>
<li>updateOne 如果查询到多条结果,只更新第一条记录。</li>
<li>upateMany 更新查询到的所有结果。</li>
<li>bulkWrite 提供可控执行顺序的批量写操作。</li>
</ul>
<p>为了代码的健壮性,我们应该根据建议将update方法换成updateMany方法。</p>
<p>另外,终端的输出<code>{ n: 1, nModified: 1, ok: 1 }</code>的意思是:</p>
<ul>
<li>“n: 1”:查询到1条记录。</li>
<li>“nModified: 1”:需要修改1条记录。(如果修改值和原始值相同,则需要修改的就是0条)</li>
<li>“ok: 1”:修改成功1条。</li>
</ul>
<h2 id="5-删除操作">5. 删除操作</h2>
<blockquote>
<p><code>remove|removeOne|removeMany|bulkWrite</code> 方法</p>
</blockquote>
<p>新建<code>remote.js</code>文件</p>
<pre><code>// remove.js file
const StudentModel = require('./StudentModel');
// delete 方法接收1个参数,就是查询条件
// 下面把name为lisi的记录删除
StudentModel.remove({name:'lisi'}).then((result) => {
console.log(result);
});
</code></pre>
<p>进入 Robo3T,可以看到集合里已经没有name为lisi的记录了:</p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0fb53e5b444d?w=2068&h=398&f=jpeg&s=130480"></p>
<p>在看终端的输出,跟update类似,也提示建议使用新的方法代替。</p>
<p><img src="https://user-gold-cdn.xitu.io/2019/10/13/16dc0fb88e8a6750?w=1550&h=184&f=jpeg&s=68730"></p>
<p>意思是建议我们使用 <code>removeOne</code>、<code>removeMany</code>或者<code>bulkWrite</code></p>
<ul>
<li>remove 删除查询到所有结果,方法已经不提倡使用,已被removeMany替代。</li>
<li>removeOne 如果查询到多条结果,只删除第一条记录。</li>
<li>removeMany 删除查询到所有结果。</li>
<li>bulkWrite 提供可控执行顺序的批量写操作。</li>
</ul>
<p>另外,终端的输出<code>{ n: 1, ok: 1, deletedCount: 1 }</code>的意思跟update的类似,就不累述了。</p>
<p>现在我们已经成功地对 MongoDB 数据库进行了 CRUD(添加、读取、更新、删除)操作。欢呼~</p>
<p>更多高级操作,可以到mongoose API 文档中查阅。</p>
<h1 id="四总结">四、总结</h1>
<p>梳理一下,主要讲了这些内容:</p>
<ol>
<li><code>node.js+MongoDB+mongoose</code> 在Mac下的环境搭建,注意使用最新的 <code>MongoDB</code> 的安装方式。</li>
<li>在Mac下如何启动和关闭 <code>MongoDB</code> 服务。</li>
<li>介绍了 <code>MongoDB</code> 和 <code>mongoose</code> 的基本核心概念。</li>
<li>使用 mongoose 连接以及增删改查 MongoDB 操作。可以使用 <code>Robo3T</code> 来更直观地观察数据库。</li>
</ol>
<p>前端也能玩转数据库开发。<br>
欢迎交流~</p>
<blockquote>
<p>文章源码地址:https://github.com/yc111/mongodb-demo</p>
</blockquote>
<p>相关网站:<br>
Homebrew官网<br>
MongoDB官网<br>
monggose官网<br>
Robo3T官网<br>
macOS 包管理器 Homebrew 移除 MongoDB</p>
<p>--<br>
欢迎转载,转载请注明出处:<br>
https://champyin.com/2019/10/10/node.js操作数据库之MongoDB+mongoose篇/</p>
<p>本文同步发表于:<br>
node.js操作数据库之MongoDB+mongoose篇 | 掘金</p><br><br>
来源:https://www.cnblogs.com/champyin/p/11666892.html
頁:
[1]