07【MongoDB】数据库概述和环境搭建,MongoDB 增删查改操作,模板引擎

    科技2022-09-04  131

    MongoDB

    数据库概述和环境搭建,MongoDB 增删查改操作,模板引擎

     

    第一部分

    1, 数据库概述和环境搭建

    1.1 为什么要使用数据库

    动态网站的数据存储在数据库中 http://www.czxy.com/artical?id=1 http://www.czxy.com/artical?id=2 id不一样页面不一样数据库用来持久存储客户端通过表单手机的用户信息

    数据库软件本身 可以对数据进行高效的管理:商品信息,用户信息分类存储,快速查找的目的;

    1.2 什么数据库

    数据库就是 存储数据的仓库,可以将数据进行有序的分门别类的存储,对数据进行高效的管理。他是独立于语言之外的 软件,通过API操作 Node.js --(数据库提供的API数据库反馈操作结果--- 据库

    常见的数据库软件:mysql(php), mongoDB, oracle;

    选择MongoDB, 开发的API 采用的也是JS 语法,和nodejs 一样,存数据的方式是 json 对象格式的,学习更加容易,更加友好

    1.3 下载安装

            MongoDB: https://www.mongodb.com/try/download/community

            MongDB compass: https://www.mongodb.com/try/download/compass

    1.4 MongoDB 可视化软件

           compass 可以通过图形界面的方式操作数据库

           nodejs 为数据库提供 API; 数据库反馈操作结果 到 Nodejs

           compass 通过界面操作数据库; 数据库通过界面反馈操作结果

    1.5 数据库  

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

     1.6 MongoDB第三方模块

    使用node.js 操作MongoDB数据库需要依赖node,js的第三方包mongoose

    npm install mongoose

    1.7 启动 mongoDB

              我们需要开启服务:打开数据库软件,才能连接;默认启动的,当电脑重新开机,关闭了如何开启?

              命令行工具:net start mongoDB / net stop mongodb

    1.8 数据库连接

    服务启动以后,如何连接数据库:connect() 方法,该方法的参数传的是连接数据库的地址和名字,

    在建立网站使用的协议是 HTTP,数据库使用的协议是 mongodb 协议;

    由于是安装到自己电脑上,所以用 localhost 访问;如果localhost后数据库名字没有,可以随便写;由于 mongoose.connect() 方法返回的是一个 promise 对象,所以就可以用.then() .catch()

    01.js 创建以及连接数据库

    // 引入mongoose第三方模块 用来操作数据库

    const mongoose = require('mongoose');

    // 数据库连接

    mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})

               // 连接成功

               .then(() => console.log('Database connection successful'))

               // 连接失败

                            .catch(err => console.log(err, 'Database connection failed'));

    在命令行:node 01.js

    (node:5004) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.

     

    出现提示: useUnifiedTopology: true 复制粘贴到 mongoose.connect()方法的第二个参数里

    【问题】

    const mongoose = require('mongoose');

    mongoose.connect('mongodb://localhost1/playground', { useNewUrlParser: true})

               .then(() => console.log('Database connection successful'))

                            .catch(err => console.log(err, 'Database connection failed'));

     

    连接://localhost1/错误,会走.catch()方法

    1.9 创建数据库

    不用显式的去创建数据库,如果正在使用的不存在,会自动帮你创建

     

    3. MongoDB 增删查改操作

    3.1 创建集合

    创建集合分两步:

    第一,先创建集合规则:在这个集合当中的文档,要拥有那些字段,字段的类型是啥,是字符串,数值,布尔值?

    第二,使用规则,创建集合

               1)创建集合规则 mongoose.Schema 创建集合规则就是创建构造函数schema的实例对象

               2)创建集合 Model()方法 mongoose 规定,集合名称首字母大写;他创建之后的会变成 小写并加上 s表示复数;这个方法返回一个 构造函数,代表当前集合;可以使用这个构造函数的方法,进行各种操作

            Model()方法中的参数:

                - 第一个参数:‘集合名称首字母大写‘,- 他自己在数据库创建的是小写而且是复数

                - 第二个参数: 集合的规则

     

     

    3.2 创建文档 - 向集合插入数据

      3.2.1 方法一: 创建集合实例

            // 连接数据库:命令行进行 node 02.js

           // 虽然连接了数据库,创建了集合,但是没有插入数据,自然不会创建数据库和集合

           // 创建文档

    创建集合实例调用实例对象下的 save() 方法保存到数据库中

    02.js 如何创建集合以及向集合中插入文档

    // 引入mongoose第三方模块 用来操作数据库

    const mongoose = require('mongoose');

    // 数据库连接

    mongoose.connect('mongodb://localhost/01test', { useNewUrlParser: true, useUnifiedTopology: true })

               // 连接成功

               .then(() => console.log('Database connection successful'))

               // 连接失败

               .catch(err => console.log(err, 'Database connection failed'));

     

    // 创建集合规则 = 创建schema的实例对象

    const courseSchema = new mongoose.Schema({

               name: String,  // 课程名字的类型

               author: String, // 课程作者类型

               isPublished: Boolean  // 课程是否发布;课程的一个状态,是布尔值

    });

     

    // 使用规则创建集合model()方法:参数有2

    // 1.集合名称:首字母大写,在数据库中起的的名字courses

    // 2.集合规则:刚才创建的集合规则;返回构造函数,用一个变量接收它

    const Course = mongoose.model('Course', courseSchema) // courses

     

    // 连接数据库:命令行进行 node 02.js;虽然连接了数据库,创建了集合,但是没有插入数据,自然不会创建数据库和集合

    // 创建文档

    const course = new Course({

               name: 'node.js1',

               author: 'luojin1',

               isPublished: true

    });

     

    // 将文档插入到数据库中

    course.save();

         3.2.2 方法二:构造函数的 create() 方法

    第二个参数回调函数,说明当前API 是 异步操作;关于数据库的所有操作都是异步的;

    在mongoose 中,所提供的API,支持两种获取API 的结果;一种就是 回调函数方式; 另一种也支持 promise 方式;就可以调用.then() .catch() 方法

     

    参数一:对象类型的文档

    参数二:回调函数;插入以后,系统调用这个回调函数,错误对象;Create也返回 Promise对象

    03.js 向集合中插入文档的另一种方式

    // 引入mongoose第三方模块 用来操作数据库

    const mongoose = require('mongoose');

    // 数据库连接

    mongoose.connect('mongodb://localhost/01test', { useNewUrlParser: true, useUnifiedTopology: true })

               // 连接成功

               .then(() => console.log('Database connection successful'))

               // 连接失败

               .catch(err => console.log(err, 'Database connection failed'));

     

    // 创建集合规则

    const courseSchema = new mongoose.Schema({

               name: String,

               author: String,

               isPublished: Boolean

    });

     

    // 使用规则创建集合

    // 1.集合名称

    // 2.集合规则

    const Course = mongoose.model('Course', courseSchema) // courses

     

    // 向集合中插入文档

    // Course.create({name: 'Javascript', author: 'luojin', isPublished: false}, (err, result) => {

    //        console.log(err)

    //        console.log(result)

    // })

    // 回调函数 说明了当前API 关于数据库的操作都是异步的;

     

    // promise 方式;

    Course.create({name: 'Javascript123', author: '黑马讲师', isPublished: false})

                 .then(result => {

                         console.log(result)

                 })

    3.3 mongoDB 数据库导入数据

    插入现成的数据;

    命令:mongoimport -d 数据库名称 -c 集合名称 -file 要导入的数据但是我们不能使用现在,因为命令行去计算机查找mongimport的可执行文件,需要手动将命令添加到系统环境变量中;找到 mongoose的可执行文件目录;复制添加到环境变量中;

    mongoimport -d 01test -c users --file ./user.json

    3.4 查询文档

    1) find() 方法也返回promise对象

    //3, 查询用户集合中的所有文档

    //User.find().then(result => console.log(result));

    //3.1 通过id字段查找

    //User.find({_id: '5c09f267aeb04b22f8460968'}).then(result => console.log(result));

    //4,返回一个,默认返回第一条

    //User.findOne().then(result => console.log(result));

    //4.1 可以加条件

    User.findOne({name: '李四'}).then(result => console.log(result));

    匹配大于,小于

    User.find({age: {$gt: 20, $lt: 50}}).then(result => console.log(result))

    匹配包含 $in 网站搜索时,在后台查询的时候用

    User.find({hobbies:{$in:['敲代码']}}).then(result => console.log(result))

    选择要查询的字段

    User.find().select('name email').then(result => console.log(result));

    根据年龄进行升序排列

    User.find().sort('age').then(result => console.log(result));

    根据年龄进行降序排列

    User.find().sort('-age').then(result => console.log(result));

    Skip 跳过多少条数据,limit限制查询数量 = 翻页使用;跳过前两个文档,只显示3个数

    User.find().skip(2).limit(3).then(result => console.log(result));

    04.js 文档查询

    // 引入mongoose第三方模块 用来操作数据库

    const mongoose = require('mongoose');

    // 数据库连接

    mongoose.connect('mongodb://localhost/01test', { useNewUrlParser: true, useUnifiedTopology: true })

               // 连接成功

               .then(() => console.log('Database connection successful'))

               // 连接失败

               .catch(err => console.log(err, 'Database connection failed'));

     

    // 创建集合规则

    const userSchema = new mongoose.Schema({

               name: String,

               age: Number,

               email: String,

               password: String,

               hobbies: [String]

    });

     

    // 使用规则创建集合

    const User = mongoose.model('User', userSchema);

     

    // 查询用户集合中的所有文档

    // User.find().then(result => console.log(result));

    // 通过_id字段查找文档

    // User.find({_id: '5c09f267aeb04b22f8460968'}).then(result => console.log(result))

     

    // findOne方法返回一条文档 默认返回当前集合中的第一条文档

    // User.findOne({name: '李四'}).then(result => console.log(result))

     

    // 查询用户集合中年龄字段大于20并且小于40的文档

    // User.find({age: {$gt: 20, $lt: 40}}).then(result => console.log(result))

     

    // 查询用户集合中hobbies字段值包含足球的文档

    // User.find({hobbies: {$in: ['足球']}}).then(result => console.log(result))

     

    // 选择要查询的字段 -_id' 加一个 - 表示不想查询的字段

    // User.find().select('name email -_id').then(result => console.log(result))

     

    // 根据年龄字段进行升序排列

    // User.find().sort('age').then(result => console.log(result))

    // 根据年龄字段进行降序排列

    // User.find().sort('-age').then(result => console.log(result))

    // 查询文档跳过前两条结果 限制显示3条结果

    User.find().skip(2).limit(3).then(result => console.log(result))

    3.5 删除文档

               1) 删除单个,也返回promise对象,通.then(); 查找到一条文档并删除,返回删除的文档,

    User.findOneAndDelete({_id: '5c09f2d9aeb04b22f846096b'}).then(result => console.log(result));

               2) 删除多个,不传全部删除,要小心, 参数也是有条件的

    User.deleteMany({}).then(result => console.log(result));

    3.6 更新文档

               1) 更新文档

               User.updateOne({查询条件},{要修改的值}).then(result => console.log(result));

               User.updateOne({name:'李四'},{name: '李狗蛋'}).then(result=>console.log(result));

               2) 更新多个

               User.updateMany({查询条件},{要修改的值}).then(result => console.log(result));

               User.updateMany({},{age: 56}).then(result=>console.log(result));

    mongoose验证

    在创建集合规则时,可以设置当前字段的验证规则,验证失败就则插入失败

    Required: true 必传字段 , 不传入报错Min/max: 针对数值这样的字段类型

    07.js

    // 引入mongoose第三方模块 用来操作数据库

    const mongoose = require('mongoose');

    // 数据库连接

    mongoose.connect('mongodb://localhost/01test', { useNewUrlParser: true, useUnifiedTopology: true })

               // 连接成功

               .then(() => console.log('Database connection successful'))

               // 连接失败

               .catch(err => console.log(err, 'Database connection failed'));

     

     

    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: '传入的值不符合验证规则'

                         }

               }

    });

    //postSchema集合规则 使用它创建一个集合

    const Post = mongoose.model('Post', postSchema);

     

    Post.create({title:'aa', age: 60, category: 'java', author: 'bd'})

               .then(result => console.log(result))

               .catch(error => {

                         // 获取错误信息对象

                         const err = error.errors;

                         // 循环错误信息对象

                         for (var attr in err) {

                                    // 将错误信息打印到控制台中

                                    console.log(err[attr]['message']);

                         }

               })

     

    集合关联(实现)

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

    使用id对集合进行关联:查找当前发布文章的作者信息

    1, 创建用户集合规则 2,创建文章集合规则/数据库中创建首字母大写的用户集合和文章集合2, 在文章集合的作者中,关联用户集合 type: mongoose.Schema.Types.ObjectId, ref: 'User'3,创建用户4, 创建一篇文章5, 查询作者信息 Post.find().populate('author').then(result=>console.log(result))

    // 引入mongoose第三方模块 用来操作数据库

    const mongoose = require('mongoose');

    // 数据库连接

    mongoose.connect('mongodb://localhost/01test', { useNewUrlParser: true, useUnifiedTopology: true })

               // 连接成功

               .then(() => console.log('Database connection successful'))

               // 连接失败

               .catch(err => console.log(err, 'Database connection failed'));

     

     

    // 用户集合规则

    const userSchema = new mongoose.Schema({

               name: {

                         type: String,

                         required: true

               }

    });

    // 文章集合规则

    const postSchema = new mongoose.Schema({

               title: {

                         type: String

               },

               // 在文章集合中存储发布文章集合的作者;集合关联

               author: {

                         // 存储用户的下划线 id值

                         type: mongoose.Schema.Types.ObjectId,

                         // 要关联的 user 集合

                         ref: 'User'

               }

    });

     

    // 创建用户集合

    const User = mongoose.model('User', userSchema);

    // 创建文章集合

    const Post = mongoose.model('Post', postSchema);

     

    // 创建用户

    // User.create({name: 'itheima'}).then(result => console.log(result));

    // 创建文章

    // Post.create({titile: '123', author: '5c0caae2c4e4081c28439791'}).then(result => console.log(result));

    Post.find().populate('author').then(result => console.log(result))

    3.8 案例: 用户的增删改查

    1)搭建网站服务器,实现客户端与服务器端的通信

    2)连接数据库,创建用户集合,向集合中插入文档

    3)当用户访问/list时,将所有的用户信息查询出来 : 路由 + 呈现用户页面

    4)将用户访问/add时,呈现表单页面,并实现添加用户信息功能

    6)当用户访问/modify时,呈现修改页面,并实现用户信息修改功能

                7) 当用户访问/delete时,实现用户删除功能

     

    第二部分

    1, 模板引擎得基础概念

    1.1 模板引擎

    第三方模块。

    让开发者以更加友好得方式拼接字符串,是项目代码更加清晰,更加易于维护

    1.2 art-template模板引擎

    1)种类很多,这个是由腾讯公司出品,目前运行最快的,公司使用最多的。

    2)下载: npm install art-template

    3)  使用:const template = require(‘art-template’) 引入;返回的是一个方法;将html 模板和数据进行拼接

    4)调用它,就告诉模板引擎要拼接的数据和模板在哪 const html = template(“模板路径,数据);第二个参数实际上是一个 对象类型,在模板中可以直接使用对象的属性来拿到对象的数据,显示到页面;在接下来,只需要模板引擎提供的特殊用法,告诉这个模板引擎,数据和模板要如何进行拼接

    1.3 案例

    // 调用 template 方法,做两件事:

    //1,要将哪一个数据和哪一个模板进行拼接;

    //2,告诉模板引擎 如何拼接?

    // template方法是用来拼接字符串的,有两个参数

    // 1. 模板路径 绝对路径 __dirname 当前文件所在目录

    // 2. 要在模板中显示的数据 对象类型

    // template() 返回拼接好的字符串

    1) 后缀 .art

     

    2. 模板引擎语法

    2.1 模板语法

            1) art-template 同时支持两种模板语法:标准语法,原始语法

            2)标准语法:容易就阅读 {{数据}}

               原始语法:强大的裸机处理能力 <%=数据 %>

    2.2 输出

    2.3 原文输出

    1)如果数据中携带 HTML标签,默认模板引擎不会解析标签会将其转义后输出

            2)标准语法:{{ @  数据 }}

            3)原始语法:<%- 数据 %>

    2.4 条件判断

            1) 在模板中可以 根据条件决定 显示那块HTML代码?

           

           

    {{if age > 18}}

               年龄大于18

    {{else if age < 15 }}

               年龄小于15

    {{else}}

               年龄不符合要求

    {{/if}}

    <% if (age > 18) { %>

               年龄大于18

    <% } else if (age < 15) { %>

               年龄小于15

    <% } else { %>

               年龄不符合要求

    <% } %>

    22.5 循环

               1)从数据库中查询数据,会返回一个数组包含多个对象,如何展示在页面中?通常采用循环的方式

               2)标准语法:{{ each 数据}} {{/each}}

               3) 原始语法: <% for() { %>    <% } %>

              

    <ul>

               {{each users}} //开始循环

                         <li>  //循环的标签

                                    {{$value.name}} //要展示的数据

                                    {{$value.age}}

                                    {{$value.sex}}

                         </li>

               {{/each}}

    </ul>

     

    2.6 子模版

              1)使用子模版 可以将 网站公共区块(头部,底部)抽离到单独的文件中去;单标记

              2)标准语法:{{include ‘子模版的路径‘}} {{include ‘./header.art’}}

               3)原始语法:<%include(‘子模版的路径‘) %> <%include(‘./header.art’) %>

    2.7 模板继承

               1) html 骨架在每个页面也属于公共部分

               2)模板继承可以 将网站HTML骨架 抽离到单独的文件中,其他页面模板可以继承骨架文件

              

              

     

    2.8 模板继承示例

    {{block ‘ ’}}预留位置 {{/block}}

    如何继承,如何填充;通过 extend

    {{extend './common/layout.art'}} // 继承layout模板

     

    {{block 'content'}}  // 填充模板中的预留的两个坑

    <p>{{ msg }}</p>

    {{/block}}

     

    {{block 'link'}}

    <link rel="stylesheet" type="text/css" href="./main.css">

    {{/block}}

    2.9 模板配置

               1) 向模板中导入变量 template.defaults.imports.变量名 = 变量值

                         - 从数据库中查时间,是原始的,不能直接显示,要处理格式化显示给用户;调用别人写好的方法;

               - 日期处理的第三方模块: dateFormat()

               - https://www.npmjs.com/package/dateformat

               - 下载: $ npm install dateformat

           - 导入: var dateFormat = require('dateformat');

               - 使用:{{dateFormat(time, 'yyyy-mm-dd')}}

              - new Date() 就是原始的时间

                 

               2)设置模板根目录 template.defaults.root = path.join(__dirname, 'views') 这样做的好处:多次重复的代码,消除

               3)设置模板默认后缀

    ——————————————————————

     

    3, 案例

     3.1 案例介绍 – 学生档案管理

              - 目标:模板引擎应用,强化node.js项目制作流程

               - 知识点:http请求响应,数据库,模板引擎,静态资源访问

               - 后期 优化代码

    3.2 项目制作流程

               1)建立项目文件夹 并 生成描述文件:package.json 文件,记录当前项目依赖的第三方模块和项目本身信息( 建立项目文件夹:students; 命令行切换到根目录:npm init -y 生成 package.json文件 )

               2) 创建数据库服务器 实现客户端和服务器端通信:基础中的基础; 建立文件夹model 分离出创建服务器代码( students文件夹下,新建一个app.js: 用来创建网站服务器并实现客户端的请求和访问;命令行:nodemon app.js 启动服务器)

               3)连接数据库 并 根据需求设计学院信息表: npm i mongoose

               创建集合规则 user.js

                  创建集合 mongoose.model()

            4)创建路由 并 实现页面模板呈递:当客户端向服务器端发送请求的时候,服务器要看一下客户端的请求路径,并根据这个路径实现一些功能和模板呈递

                         - npm install router

    - 下载模板引擎 npm i art-template

               5)实现静态资源访问: 发送请求的css, js, 图片文件等

               6)实现学生信息添加功能

               7)实现学生信息展示功能

    3.3 第三方模块 router

               - 功能:实现路由

               - 使用步骤:1,获取路由对象

                             2,调用路由对象提供的方法创建路由

                             3,启用路由,使路由生效

               -代码: npm install router

                         、

    3.4 第三方模块 serve-static

               - 功能:实现静态资源访问功能

               - 使用步骤:

                         1,引入serve-static 模块获取创建静态资源服务功能的方法

                         2,调用方法创建静态资源服务并指定静态资源服务目录,当参数传递给他

                         3,启用静态资源服务功能:调用它

    代码:npm install servestatic

    3.5. 添加学生信息功能步骤分析

               1)需要向服务器发请求的post,在模板的表单(action,method)中执行请求地址与请求方式

               2)为每一个表单添加name属性

               3)添加实现信息功能路由,处理请求

               4)接收客户端请求来的学生信息

               5)将学生信息太牛加到数据库

               6)将页面重定向到学生信息页面

    3.6 学生信息列表页面分析

               1)将数据库中多有的学生信息查询出来

               2)通过模板引擎将学生信息和HTML模板进行拼接

               3)将拼接好的模板响应给客户端

              - npm install dateformat 处理时间

    model: 数据库相关代码

    public: 静态资源

    route: 路由

    views: 模板

    app.js: 入口文件,主文件

     

     

     

    Processed: 0.008, SQL: 9