1. init

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

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

npm install mongoose        // 第三方模块
net start mongoDB           // 启动数据库

为什么选择MongoDB?
    => 该数据库开发的API是采用JavaScript的语法;
       存储的数据是以json对象格式; 
       更适合前端人员进行开发;

nodejs axios监听下载进度 nodejs监听数据库变化_nodejs axios监听下载进度

2. 插入数据

// 02_插入数据.js
/**
 * mongoose: 第三方模块:需要下载
 * 某个API文档: http://www.mongoosejs.net/docs/guide.html
 */
const mongoose = require('mongoose');

/* 1. 连接数据库: student就是数据库名, 没有则自动创建该数据库 */
mongoose.connect('mongodb://localhost/student', { useNewUrlParser: true , useUnifiedTopology: true })
    .then(() => { console.log('connect database success!'); })
    .catch((error)=>{ console.log(error,'connect database failed!'); });


    
/* 2. 创建集合规则: 使用Schema()就相当于创建字段; */
const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    isPublished: Boolean
});


/* 3. 使用集合规则创建集合(集合 === 表),返回一个构造函数; 
      实际上此时就相当于创建了一张表, 表的字段就是刚才创建的集合规则;  
      使用model方法就相当于创建表; */
const Course = mongoose.model('Course', courseSchema);  // 在MongoDB中显示为courses



/* 4. 插入数据 
    (1) 创建文档(相当于插入行,文档 === 行); 
    (2) 创建文档实际上就是向集合中插入数据; 
*/
/* 
法一:实例化构造函数(实例化集合)

    const data1 = new Course({
        name: 'nodeJS',
        author: 'teacher',
        isPublished: true
    });
    data1.save();       //表示插入到数据库中
*/

/* 法二:表示插入到数据库之中
    (1) 插入单条数据
        Course.create({name: 'JS', author: 'student', isPublished: false}, (error, doc) => {
            // console.log(err);        // 错误对象
            console.log(doc);           // 当前插入的文档
        });
    (2) 插入多条数据
    user.create(
        { name: 'zhang', age: 12, password: '123456', hobbies: ['sing', 'dance'] },
        { name: 'wang', age: 23, password: '654321', hobbies: ['say', 'pao'] },
        { name: 'li', age: 45, password: '654321', hobbies: ['say', 'pao'] },
        { name: 'zhao', age: 24, password: '654321', hobbies: ['say', 'pao'] },
        { name: 'gao', age: 522, password: '654321', hobbies: ['say', 'pao'] }
    );

*/


// create也返回Promise对象
Course.create({ name:'JavaScript', author:'GaoSan111', isPublished:false })
    .then((doc)=> {
        console.log(doc);
    })
    .catch((err)=>{
        console.log(err);
    });

nodejs axios监听下载进度 nodejs监听数据库变化_字段_02

3. 查询数据

// 03_查询数据.js

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
        useNewUrlParser: true,
        useUnifiedTopology: true
    })
    .then(() => {
        console.log('connect server success!');
    })
    .catch((error) => {
        console.log(error, 'connect server failed!');
    });

/*
    此处注意:虽然是在图形化工具中创建了表;
    但是要以代码的形式引用该表, 仍然需要使用.model()方法;
    同时需要将.model()中的'User'设置为大写, 
    因为User会被默认转化为uses, 这可不就是我们所创建的表吗; 
*/
const user = mongoose.model('User', new mongoose.Schema({
    num: Number,
    name: String,
    age: Number,
    hobbies: []
}));


/* 
    [1]. find(): 查询结果以数组形式进行返回, 查询所有文档(所有行); 

    user.find().then((result) => {
        console.log(result);
    });
*/

/* 
    [2]. 指定条件查询: 

    user.find({
        _id: '6151d120b3d9e081c196d7c9'
    }).then((result) => {
        console.log(result);
    }); 
*/


/* 
    [3]. findOne(): 不传参数,则默认返回第一个文档(第一行); 

    user.findOne({
        name: 'Jing'
    }).then((result) => {
        console.log(result);
    }); 
*/


/* 
    [4]. find条件系列查找:匹配大于,小于; 
        (1) $gt: 匹配大于;
        (2) $lt:匹配小于; 
            //20 < age < 40
            user.find({age: {$gt: 20, $lt: 40}}).then((result)=>{
                    console.log(result);
            }); 
        (3) $in: 匹配包含; 
            user.find({
                hobbies: {
                    $in: ['sing']
                }
            }).then((result) => {
                console.log(result);
            }); 
        (4) 选择要查询的字段:不显示_id字段; 
            使用字符串语法时,有 -前缀的路径会被排除,没有 -前缀的路径会被选择; 
            user.find().select('name password -_id').then((result) => {
                console.log(result);
            }); 

user.find({
    age: {
        $gt: 20,
        $lt: 30
    }
}).then((result) => {
    console.log(result);
});

user.find({
    hobbies: {
        $in: ['dance']
    }
}).then((result) => {
    console.log(result);
});

user.find().select('num name -_id').then((result) => {
    console.log(result);
});*/



/*
    [5]. 排序:每个字段的排列顺序默认是升序,如果字段名有 - 前缀, 那么这个字段是降序; 
        升序:
            user.find().sort('age').then((result)=>{
                console.log(result);
            }); 
        降序:
            user.find().sort('-age').then((result) => {
                console.log(result); 
            }); 


    user.find().sort('age').then((result) => {
        console.log(result);
    });

    user.find().sort('-age').then((result) => {
        console.log(result);
    });
*/


/*
    [6]. 限制查询:
    跳过2条,限制查询的数量数量为2个
         user.find().skip(2).limit(2).then((result) => {
            console.log(result);
        });       
*/

user.find().skip(2).limit(2).then((result) => {
    console.log(result);
});

nodejs axios监听下载进度 nodejs监听数据库变化_nodejs axios监听下载进度_03

4. 删除数据

// 04_删除数据.js

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
        useNewUrlParser: true,
        useUnifiedTopology: true
    })
    .then(() => {
        console.log('connect database success!');
    })
    .catch((error) => {
        console.log(error, 'connect database failed!');
    });

const user = mongoose.model('User', new mongoose.Schema({
    num: Number,
    name: String,
    age: Number,
    hobbies: []
}));


/*
    1. 删除单条记录( findOneAndDelete() )
        删除一个:如果查询结果包含多条记录,则删除匹配文档中的第一个,并返回删除的这个对象; 
*/
/* */
user.findOneAndDelete({
    name: 'GaoSan'
}).then((result) => {
    console.log(result);
});



/* 
    2. 删除多条记录( deleteMany() )
*/
/*  
    此时会将表中的所有记录删除; 

user.deleteMany({}).then((result) => {
    console.log(result);
});
*/

nodejs axios监听下载进度 nodejs监听数据库变化_字段_04

5. 更新数据

// 05_更新数据.js

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
        useNewUrlParser: true,
        useUnifiedTopology: true
    })
    .then(() => {
        console.log('connect database success!');
    })
    .catch((error) => {
        console.log(error, 'connect server failed!');
    });
const user = mongoose.model('User', new mongoose.Schema({
    num: Number,
    name: String,
    age: Number,
    hobbies: []
}));


/*
    1. 更新一条:(更改的条目,更改后条目的值)
*/
/* */
    user.updateOne( { name: "XingWei" }, { name: "XingWeiZi" } ).then((result) => {
        console.log(result);
    }); 


/*
    2. 更新多条:{} => 所有

user.updateMany({}, {
    "age": 99
}).then((result) => {
    console.log(result);
}); 
*/

nodejs axios监听下载进度 nodejs监听数据库变化_mongodb_05

6. 检验规则

// 06_校验规则.js

/* 
    在创建集合规则时,可以设置当前字段的验证规则,验证失败就则输入插入失败; 
    required:true           必传字段·minlength:3字符串最小长度
    maxlength:             20字符串最大长度
    min:2                  数值最小为2
    max:100                数值最大为100
    enum: [html,'css]      插入的值必须是枚举中的任意一个
    trim: true              去除字符串两边的空格
    validate:              自定义验证器
    default:               默认值 
*/

//验证规则
const { log } = require('console');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
        useNewUrlParser: true,
        useUnifiedTopology: true
    })
    .then(() => {
        console.log('connect database success!');
    })
    .catch((error) => {
        console.log(error, 'connect database failed!');
    });
const personSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, 'the name filed must to be write!'], // 此时这个字段必须赋值,否则ERROR数组; 里的第二个表示自定义ERROR信息
        minlength: [2, '不能小于2个字符'], // 针对String类型
        maxlength: [5, '不能大于5个字符'],
        trim: true,
    },
    age: {
        type: Number,
        min: 2, // 针对数值类型
        max: [8, '传入的数值过大!'],
    },
    publishDate: {
        type: Date,
        default: Date.now // 默认值
    },
    category: {
        type: String,
        enum: {
            values: ['c++', 'css', 'html'], // 只能取指定的值
            message: '必须是指定值之一'
        }
    },
    author: { //自定义规则
        type: String,
        validate: {
            validator: (value) => { // value: 用户传递的值; 返回true,验证成功; 返回false,验证失败
                return value && value.length > 4;
            },
            message: '传入的值不符合自定义规则' // 自定义错误信息
        }
    }
});

const person = mongoose.model('Teacher', personSchema);
person.create({
        name: 'Good',
        age: 6,
        category: 'c+',
        author: 'bdddd'
    })
    .then((result) => {
        console.log(result);
    })
    .catch((error) => {
        // console.log(error);
        const errors = error.errors; // errors是一个对象
        // console.log(errors);
        for (var attr in errors) {
            // console.log('***> ' + attr);
            // console.log(errors[attr]);
            console.log(errors[attr]['message']);
        }
    });

/* 
也即是errors就是这样一个对象:
    {
    category: ValidatorError: 必须是指定值之一
        at validate (F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\schematype.js:1237:13)
        at F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\schematype.js:1220:7
        at Array.forEach (<anonymous>)
        at SchemaString.SchemaType.doValidate (F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\schematype.js:1165:14)
        at F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\document.js:2506:18
        at processTicksAndRejections (internal/process/task_queues.js:77:11) {
        properties: {
        validator: [Function (anonymous)],
        message: '必须是指定值之一',
        type: 'enum',
        enumValues: [Array],
        path: 'category',
        value: 'c+'
        },
        kind: 'enum',
        path: 'category',
        value: 'c+',
        reason: undefined,
        [Symbol(mongoose:validatorError)]: true
    }
    }
*/

7. 集合校验

// 07_集合关联.js
/* 
    集合关联:通常不同集合的数据之间是有关系的; (也就是数据表的关联)
*/
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
        useNewUrlParser: true,
        useUnifiedTopology: true
    })
    .then(() => {
        console.log('connect database success!');
    })
    .catch((error) => {
        console.log(error, 'connect database failed!');
    });


/* 1.  */
const authorSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true
    }
});
const articleSchema = new mongoose.Schema({
    title: {
        type: String
    },
    //使用id将两个表进行关联;表示author这个字段和Author这个表进行关联
    author: {
        type: mongoose.Schema.Types.ObjectId, // _id, 存储的是作者的id
        ref: 'Author' // 关联的表
    }
});


/* 2. */
const author = mongoose.model('Author', authorSchema); //  作者表格
const article = mongoose.model('Article', articleSchema); //  文章表格

/*
    // 1. 首先插入一个作者
    author.create({name: '路遥'}).then((result)=>{
        console.log(result);
    }); 
        结果如下:
            _id : 615315fd1308cb61a87112dc
            name : "路遥"
            __v : 0

    // 1. 然后将作者的_id字段值给拷过来, 赋值给article表中的author字段
    article.create({ title: '完美世界', author: '615315fd1308cb61a87112dc' }).then((result) => {
        console.log(result);           
    });         
        结果如下:
            _id : 6153167832f6c458609154de
            title : "完美世界"
            author : 615315fd1308cb61a87112dc
            __v : 0

    // 3. 此后查询即可
*/


// 单纯的查询article表 => author字段显示的只是作者的_id字段的标识符
article.find()
    .then((result) => {
        console.log(result);
    });
/*
    [
        {
            _id: 6153167832f6c458609154de,
            title: '完美世界',
            author: 615315fd1308cb61a87112dc,
            __v: 0
        }
    ]
*/


// 联合查询populate(): 指定哪些字段需要关联查询(populated)其他文档; 
// 此时在author字段, 已将作者的信息以对象的形式给展示出来了;
// ```populate()就是将author字段对应的作者信息给详细展示出来 ```;  
article.find()
    .populate('author')
    .then((result) => {
        console.log(result);
    });
/* 
    [
        {
            _id: 6153167832f6c458609154de,
            title: '完美世界',
            author: { _id: 615315fd1308cb61a87112dc, name: '路遥', __v: 0 },
            __v: 0
        }
    ]
*/

nodejs axios监听下载进度 nodejs监听数据库变化_数据库_06



联合查询解释:

nodejs axios监听下载进度 nodejs监听数据库变化_nodejs axios监听下载进度_07