2025年数据库概念&mongodb使用&数据库CLUD操作

数据库概念&mongodb使用&数据库CLUD操作数据库概念 amp 环境搭建 目标 能够安装数据库软件 能够知道集合 文档的概念 能够使用 mongoose 创建集合的方法创建集合 为什么要使用数据库 动态网站中的数据都是存储在数据库中的 数据库可以用来持久存储客户端通过表单收集的用户信息 数据库软件本身可以对数据进行高效的管理 什么是数据库

大家好,我是讯享网,很高兴认识大家。

数据库概念&环境搭建

目标

  • 能够安装数据库软件
  • 能够知道集合、文档的概念
  • 能够使用mongoose创建集合的方法创建集合

为什么要使用数据库(★★★)

  • 动态网站中的数据都是存储在数据库中的
  • 数据库可以用来持久存储客户端通过表单收集的用户信息
  • 数据库软件本身可以对数据进行高效的管理

什么是数据库(★★★)

  • 数据库即存储数据的仓库,可以将数据进行有序的分门别类的存储。它是独立于语言之外的软件,可以通过API去操作它。
  • 常见的数据库软件有:mysql、mongoDB、oracle。

MongoDB数据库下载安装(★★★)

下载地址:https://www.mongodb.com/download-center/community

[外链图片转存失败(img-HRsJ9Brw-11)(images/mongodb.png)]

MongoDB可视化软件

MongoDB可视化操作软件,是使用图形界面操作数据库的一种方式。

[外链图片转存失败(img-xF7kGxMN-12)(images/sql-keshihua.png)]

数据库相关概念(★★★)

在一个数据库软件中可以包含多个数据仓库,在每个数据仓库中可以包含多个数据集合,每个数据集合中可以包含多条文档(具体的数据)。

术语 解释说明
database 数据库,mongoDB数据库软件中可以建立多个数据库
collection 集合,一组数据的集合,可以理解为JavaScript中的数组
document 文档,一条具体的数据,可以理解为JavaScript中的对象
field 字段,文档中的属性名称,可以理解为JavaScript中的对象属性

Mongoose第三方包

  • 使用Node.js操作MongoDB数据库需要依赖Node.js第三方包mongoose
  • 使用npm install mongoose命令下载

启动MongoDB

在命令行工具中运行net start mongoDB即可启动MongoDB,否则MongoDB将无法连接。

MongoDB增删改查(CLUD)操作

目标

  • 能够对数据库中的数据进行增删改查操作

数据库连接(★★★)

使用mongoose提供的connect方法即可连接数据库。

// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { 
    useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); 

讯享网

创建集合(创建表)(★★★)

创建集合分为两步,一是对对集合设定规则,二是创建集合,创建mongoose.Schema构造函数的实例即可创建集合。

讯享网 // 设定集合规则 const courseSchema = new mongoose.Schema({ 
    name: String, author: String, isPublished: Boolean }); // 创建集合并应用规则 const Course = mongoose.model('Course', courseSchema); // courses 

创建文档(插入数据)(★★★)

创建文档实际上就是向集合中插入数据。

分为两步:

  • 创建集合实例。
  • 调用实例对象下的save方法将数据保存到数据库中。
// 创建集合实例 const course = new Course({ 
    name: 'Node.js course', author: '黑马讲师', tags: ['node', 'backend'], isPublished: true }); // 将数据保存到数据库中 course.save(); 

插入数据另外一种方法

讯享网//写法一 Course.create({ 
   name: 'JavaScript基础', author: '黑马讲师', isPublish: true}, (err, doc) => { 
    // 错误对象 console.log(err) // 当前插入的文档 console.log(doc) }); //写法二 Course.create({ 
   name: 'JavaScript基础', author: '黑马讲师', isPublish: true}) .then(doc => console.log(doc)) .catch(err => console.log(err)) 

mongoDB数据库导入数据

找到mongodb数据库的安装目录,将安装目录下的bin目录放置在环境变量中

[外链图片转存失败(img-IEu9Td2C-14)(images/mongodb-path.png)]

mongoimport –d 数据库名称 –c 集合名称 –-file 要导入的数据文件

mongoimport -d test -c users --file 数据文件的路径 

查询文档(数据)(★★★)

利用find的方法查询

查询所有(★★★)

讯享网//定义好表规则 const user = new mongodb.Schema({ 
    _id: String, username: String, password: Number, age: Number, name: String, hobbies: [String], email: String }); //生成对应的对象索引 const userEntity = mongodb.model('User', user); // 根据条件查找文档(条件为空则查找所有文档) Course.find().then(result => console.log(result)) // 返回文档集合 [{ 
    _id: 5c0917ed37ec9b03c07cf95f, name: 'node.js基础', author: '黑马讲师‘ },{ 
    _id: 5c09dea28acfbff827, name: 'Javascript', author: '黑马讲师‘ }] 

根据条件查询(★★★)

//定义好表规则 const user = new mongodb.Schema({ 
    _id: String, username: String, password: Number, age: Number, name: String, hobbies: [String], email: String }); //生成对应的对象索引 const userEntity = mongodb.model('User', user); // 根据条件查找文档 userEntity.findOne({ 
   name: 'node.js基础'}).then(result => console.log(result)) // 返回文档 { 
    _id: 5c0917ed37ec9b03c07cf95f, name: 'node.js基础', author: '黑马讲师‘ } 

多条件查询(★★)

根据范围查询
讯享网// 匹配大于 小于 userEntity.find({ 
   age: { 
   $gt: 20, $lt: 50}}).then(result => console.log(result)) 

包含某字符

 // 匹配包含 userEntity.find({ 
   hobbies: { 
   $in: ['敲代码']}}).then(result => console.log(result)) 
查询某一个字段
讯享网// 选择要查询的字段  userEntity.find().select('name email').then(result => console.log(result)) 
排序查询
 // 将数据按照年龄进行排序 升序 userEntity.find().sort('age').then(result => console.log(result)) // 将数据按照年龄进行排序 降序 userEntity.find().sort('-age').then(result => console.log(result)) 
分页查询
讯享网// skip 跳过多少条数据 limit 查询几条数据 userEntity.find().skip(2).limit(2).then(result => console.log(result)) 

删除文档(★★★)

删除单条数据
//定义好表规则 const user = new mongodb.Schema({ 
    _id: String, username: String, password: Number, age: Number, name: String, hobbies: [String], email: String }); //生成对应的对象索引 const userEntity = mongodb.model('User', user); // 删除单个 userEntity.findOneAndDelete({ 
   }).then(result => console.log(result)) 
删除多个数据
讯享网//定义好表规则 const user = new mongodb.Schema({ 
    _id: String, username: String, password: Number, age: Number, name: String, hobbies: [String], email: String }); //生成对应的对象索引 const userEntity = mongodb.model('User', user); // 删除多个 userEntity.deleteMany({ 
   }).then(result => console.log(result)) 

更新文档(★★★)

更新单条数据
// 更新单个 User.updateOne({ 
   查询条件}, { 
   要修改的值}).then(result => console.log(result)) 
更新多条数据
讯享网// 更新多个 User.updateMany({ 
   查询条件}, { 
   要更改的值}).then(result => console.log(result)) 

mongoose验证(★★)

在创建集合规则时,可以设置当前字段的验证规则,验证失败就则输入插入失败。说白了,就是规定我们插入数据库每一项的条件

  • required: true 必传字段
  • minlength:3 字符串最小长度
  • maxlength: 20 字符串最大长度
  • min: 2 数值最小为2
  • max: 100 数值最大为100
  • enum: [‘html’, ‘css’, ‘javascript’, ‘node.js’]
  • trim: true 去除字符串两边的空格
  • validate: 自定义验证器
  • default: 默认值

代码示例

const postSchema = new mongoose.Schema({ 
    title: { 
    type: String, // 必选字段 required: [true, '请传入文章标题'], // 字符串的最小长度 minlength: [2, '文章长度不能小于2'], // 字符串的最大长度 maxlength: [5, '文章长度最大不能超过5'], // 去除字符串两边的空格 trim: true }, age: { 
    type: Number, // 数字的最小范围 min: 18, // 数字的最大范围 max: 100 }, publishDate: { 
    type: Date, // 默认值 default: Date.now }, category: { 
    type: String, // 枚举 列举出当前字段可以拥有的值 enum: { 
    values: ['html', 'css', 'javascript', 'node.js'], message: '分类名称要在一定的范围内才可以' } }, author: { 
    type: String, validate: { 
    validator: v => { 
    // 返回布尔值 // true 验证成功 // false 验证失败 // v 要验证的值 return v && v.length > 4 }, // 自定义错误信息 message: '传入的值不符合验证规则' } } }); 
如何捕获验证的错误信息
讯享网.catch(error => { 
    // 获取错误信息对象 const err = error.errors; // 循环错误信息对象 for (var attr in err) { 
    // 将错误信息打印到控制台中 console.log(err[attr]['message']); } }) 

集合关联(★★)

通常不同集合的数据之间是有关系的,例如文章信息和用户信息存储在不同集合中,但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要用到集合关联。

  • 使用id对集合进行关联
  • 使用populate方法进行关联集合查询

[外链图片转存失败(img-xGEmEFdm-19)(images/关联查询.png)]

示例demo
// 用户集合 const User = mongoose.model('User', new mongoose.Schema({ 
    name: { 
    type: String } })); // 文章集合 const Post = mongoose.model('Post', new mongoose.Schema({ 
    title: { 
    type: String }, // 使用ID将文章集合和作者集合进行关联 author: { 
    type: mongoose.Schema.Types.ObjectId, ref: 'User' } })); const userEntity = mongodb.model('User', user); const postEntity = mongodb.model('Post', title); //1.插入数据的时候需要关联起来 userEntity.create({ 
    name: '王五' }).then(result => console.log(result)); postEntity.create({ 
    title: '射雕英雄传', author: '5c95ac7d18f84d8fac8ee4e1' }).then(resule => console.log(result)); //联合查询 postEntity.find() .populate('author') .then((err, result) => console.log(result)); 

用户信息增删改查(★★★)

功能

搭建网站服务器,实现客户端与服务器端的通信
连接数据库,创建用户集合,向集合中插入文档
当用户访问/list时,将所有用户信息查询出来
将用户信息和表格HTML进行拼接并将拼接结果响应回客户端
当用户访问/add时,呈现表单页面,并实现添加用户信息功能
当用户访问/modify时,呈现修改页面,并实现修改用户信息功能
当用户访问/delete时,实现用户删除功能

步骤

1.创建服务器

讯享网const http = require('http'); const app = http.createServer(); 

2.引入mongodb模块,链接数据库

const mongoose = require('mongoose'); // 数据库连接 27017是mongodb数据库的默认端口 mongoose.connect('mongodb://localhost/playground', { 
    useNewUrlParser: true }) .then(() => console.log('数据库连接成功')) .catch(() => console.log('数据库连接失败')); 

3.创建用户表规则,获取集合

讯享网const userSchema = new mongoose.Schema({ 
    name: { 
    type: String, required: true, minlength: 2, maxlength: 20 }, age: { 
    type: Number, min: 18, max: 80 }, password: String, email: String, hobbies: [ String ] }); // 创建集合 返回集合构造函数 const User = mongoose.model('User', userSchema); 

4.导入用户的数据

mongoimport -d test -c users --file 数据文件的路径 

5.当用户访问/list时,将所有用户信息查询出来

5.1 实现路由功能,利用 request对象的method来判断是什么请求,然后拿到请求的path路径,根据不同的path路径来实现不同的功能逻辑,

5.2 如果是list,查询用户信息,然后遍历用户数据,拼接获取的数据,渲染到页面

5.3 如果是add,跳转到添加页面


讯享网

5.4 如果是modify,跳转到用户修改页面,根据用户id查询出用户的所有信息,显示在页面

5.4 如果是remove,根据用户的id,来删除这条数据,然后重新挑换到list页面

5.5 如果是post请求,路径是add,说明用户点击了提交,需要获取用户信息,然后插入到数据库

5.6 如果是post请求,路径是modify,说明用户点击了修改,需要拿到信息,根据用户id来修改数据库里面的数据

讯享网// 为服务器对象添加请求事件 app.on('request', async (req, res) => { 
    // 请求方式 const method = req.method; // 请求地址 const { 
    pathname, query } = url.parse(req.url, true); if (method == 'GET') { 
    // 呈现用户列表页面 if (pathname == '/list') { 
    // 查询用户信息 let users = await User.find(); // html字符串,拼接html的内容 let list ='<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户列表</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> </head> <body> <div class="container"> <h6> <a href="/add" class="btn btn-primary">添加用户</a> </h6> <table class="table table-striped table-bordered"> <tr> <td>用户名</td> <td>年龄</td> <td>爱好</td> <td>邮箱</td> <td>操作</td> </tr>'; //拿到了用户的信息,用户的信息可能不只一条,所以我们需要去遍历用户信息来拼接里面的内容 users.forEach(item => { 
    list += ` <tr> <td>${ 
     item.name}</td> <td>${ 
     item.age}</td> <td> `; //一个用户会有多个爱好,所以需要进行遍历 item.hobbies.forEach(item => { 
    list += `<span>${ 
     item}</span>`; }) list += `</td> <td>${ 
     item.email}</td> <td> <a href="/remove?id=${ 
     item._id}" class="btn btn-danger btn-xs">删除</a> <a href="/modify?id=${ 
     item._id}" class="btn btn-success btn-xs">修改</a> </td> </tr>`; }); //拼接HTML页面剩余的标签 list += ` </table> </div> </body> </html> `; //代码执行到这里,所有的数据已经拼接完毕,需要返回给页面 res.end(list); }else if (pathname == '/add') { 
    // 呈现添加用户表单页面 let add = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户列表</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> </head> <body> <div class="container"> <h3>添加用户</h3> <form method="post" action="/add"> <div class="form-group"> <label>用户名</label> <input name="name" type="text" class="form-control" placeholder="请填写用户名"> </div> <div class="form-group"> <label>密码</label> <input name="password" type="password" class="form-control" placeholder="请输入密码"> </div> <div class="form-group"> <label>年龄</label> <input name="age" type="text" class="form-control" placeholder="请填写邮箱"> </div> <div class="form-group"> <label>邮箱</label> <input name="email" type="email" class="form-control" placeholder="请填写邮箱"> </div> <div class="form-group"> <label>请选择爱好</label> <div> <label class="checkbox-inline"> <input type="checkbox" value="足球" name="hobbies"> 足球 </label> <label class="checkbox-inline"> <input type="checkbox" value="篮球" name="hobbies"> 篮球 </label> <label class="checkbox-inline"> <input type="checkbox" value="橄榄球" name="hobbies"> 橄榄球 </label> <label class="checkbox-inline"> <input type="checkbox" value="敲代码" name="hobbies"> 敲代码 </label> <label class="checkbox-inline"> <input type="checkbox" value="抽烟" name="hobbies"> 抽烟 </label> <label class="checkbox-inline"> <input type="checkbox" value="喝酒" name="hobbies"> 喝酒 </label> <label class="checkbox-inline"> <input type="checkbox" value="烫头" name="hobbies"> 烫头 </label> </div> </div> <button type="submit" class="btn btn-primary">添加用户</button> </form> </div> </body> </html> `; res.end(add); }else if (pathname == '/modify') { 
    //如果是修改页面,呈现修改的页面,修改肯定是修改某一个用户的信息,需要根据用户的id来进行查询 let user = await User.findOne({ 
   _id: query.id}); let hobbies = ['足球', '篮球', '橄榄球', '敲代码', '抽烟', '喝酒', '烫头', '吃饭', '睡觉', '打豆豆'] console.log(user) // 呈现修改用户表单页面 let modify = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户列表</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> </head> <body> <div class="container"> <h3>修改用户</h3> <form method="post" action="/modify?id=${ 
     user._id}"> <div class="form-group"> <label>用户名</label> <input value="${ 
     user.name}" name="name" type="text" class="form-control" placeholder="请填写用户名"> </div> <div class="form-group"> <label>密码</label> <input value="${ 
     user.password}" name="password" type="password" class="form-control" placeholder="请输入密码"> </div> <div class="form-group"> <label>年龄</label> <input value="${ 
     user.age}" name="age" type="text" class="form-control" placeholder="请填写邮箱"> </div> <div class="form-group"> <label>邮箱</label> <input value="${ 
     user.email}" name="email" type="email" class="form-control" placeholder="请填写邮箱"> </div> <div class="form-group"> <label>请选择爱好</label> <div> `; hobbies.forEach(item => { 
    // 判断当前循环项在不在用户的爱好数据组 let isHobby = user.hobbies.includes(item); if (isHobby) { 
    modify += ` <label class="checkbox-inline"> <input type="checkbox" value="${ 
     item}" name="hobbies" checked> ${ 
     item} </label> ` }else { 
    modify += ` <label class="checkbox-inline"> <input type="checkbox" value="${ 
     item}" name="hobbies"> ${ 
     item} </label> ` } }) modify += ` </div> </div> <button type="submit" class="btn btn-primary">修改用户</button> </form> </div> </body> </html> `; res.end(modify); }else if (pathname == '/remove') { 
    //删除根据用户id进行删除 await User.findOneAndDelete({ 
   _id: query.id}); //通过301的相应码进行重定向 res.writeHead(301, { 
    Location: '/list' }); res.end(); } }else if (method == 'POST') { 
    // 用户添加功能 if (pathname == '/add') { 
    // 接受用户提交的信息 let formData = ''; // 接受post参数,这是一个持续的过程,我们不知道什么时候传递好了,需要在end里面去进行监听 req.on('data', param => { 
    formData += param; }) // post参数接受完毕 req.on('end', async () => { 
    //利用 querystring来进行数据的解析 let user = querystring.parse(formData) // 将用户提交的信息添加到数据库中 await User.create(user); // 301代表重定向 // location 跳转地址 res.writeHead(301, { 
    Location: '/list' }); res.end(); }) }else if (pathname == '/modify') { 
    // 接受用户提交的信息 let formData = ''; // 接受post参数 req.on('data', param => { 
    formData += param; }) // post参数接受完毕 req.on('end', async () => { 
    let user = querystring.parse(formData) // 将用户提交的信息添加到数据库中 await User.updateOne({ 
   _id: query.id}, user); // 301代表重定向 // location 跳转地址 res.writeHead(301, { 
    Location: '/list' }); res.end(); }) } } }); // 监听端口 app.listen(3000); 

相关模块方法

url模块

专门用来处理请求路径相关

url.parse(urlString,boolean,boolean)

parse这个方法可以将一个url的字符串解析并返回一个url的对象

urlString 传入一个url地址的字符串

第二个参数(可省):如果设为 true,则返回的 URL 对象的 query 属性会是一个使用 querystring 模块的 parse() 生成的对象。 如果设为 false,则 query 会是一个未解析未解码的字符串。 默认为 false

例如:

[外链图片转存失败(img-ciOqEdko-20)(images/url-true.png)]

第三个参数(可省):如果设为 true,则 // 之后至下一个 / 之前的字符串会解析作为 host。 例如, //foo/bar 会解析为 {host: 'foo', pathname: '/bar'} 而不是 {pathname: '//foo/bar'}。 默认为 false

url.format(urlObj)

format这个方法是将传入的url对象编程一个url字符串并返回

url.format({ 
    protocol:"http:", host:"182.163.0:60", port:"60" }); /* 返回值: 'http://182.163.0:60' */ 

url.resolve(from, to)

resolve这个方法返回一个格式为"from/to"的字符串,把参数进行一个拼接,然后返回

讯享网const url = require('url'); url.resolve('/one/two/three', 'four'); // '/one/two/four' url.resolve('http://example.com/', '/one'); // 'http://example.com/one' url.resolve('http://example.com/one', '/two'); // 'http://example.com/two' 

querystring模块

querystring从字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析

querystring.parse(str,separator,eq,options)

parse这个方法是将一个字符串反序列化为一个对象。

str:指需要反序列化的字符串;

separator(可省):指用于分割str这个字符串的字符或字符串,默认值为"&";

eq(可省):指用于划分键和值的字符或字符串,默认值为"=";

decodeURIComponent:传入一个function,用于对含有%的字符串进行解码,默认值为querystring.unescape,默认是utf-8的编码,如果不是需要进行定义

// 假设 gbkDecodeURIComponent 函数已存在。 querystring.parse('w=%D6%D0%CE%C4&foo=bar', null, null, { 
    decodeURIComponent: gbkDecodeURIComponent }); 

querystring.stringify(obj,separator,eq,options)

stringify这个方法是将一个对象序列化成一个字符串,与querystring.parse相对。

obj:指需要序列化的对象

separator(可省):用于连接键值对的字符或字符串,默认值为"&";

eq(可省):用于连接键和值的字符或字符串,默认值为"=";

options(可省):传入一个对象,该对象可设置encodeURIComponent这个属性:

encodeURIComponent:值的类型为function,可以将一个不安全的url字符串转换成百分比的形式,默认值为querystring.escape()。

讯享网querystring.stringify({ 
   name: 'heima', sex: [ 'man', 'women' ] }); /* return: 'name=heima&sex=man&sex=women' */ 

querystring.escape(str)

escape可使传入的字符串进行编码

querystring.escape("name=黑马程序员"); /* return: 'name%3D%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98' */ 

querystring.unescape(str)

unescape方法可将含有%的字符串进行解码

讯享网querystring.unescape('name%3D%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98'); /* return: 'name=黑马程序员' */ 
小讯
上一篇 2025-03-30 13:16
下一篇 2025-04-11 12:08

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/46962.html