美文网首页基础前端
mongoose 入门指引

mongoose 入门指引

作者: CondorHero | 来源:发表于2019-08-14 12:32 被阅读1次
    一、快速入门

    nodejs 安装 mongoose

    npm install --save mongoose
    

    现在往 dbs 这个数据库里面添加一个 students 文档(表)并写入一条数据。

    // 引入mongoose,mongoose的依赖中自动有mongodb的,所以不需要再次引入mongodb
    var mongoose = require('mongoose');
    
    //链接数据库,端口号不需要写,最后的反斜杠是数据库名字
    mongoose.connect('mongodb://localhost/dbs', {useNewUrlParser: true});
    
    //用mongoose.model()函数创建一个模型,是一个类。此时你传入的第一个参数将自动大写变为小写,末尾加s,变为集合名字。
    //第二个参数是schema,就是字段列表,用kv对表示字段名字和类型。
    var Student = mongoose.model('Student', { 
        class : String,
        name : String,
        sex : String,
        age : Number,
        height : Number,
        weight : Number
    });
    
    //实例化对象
    var huayue = new Student({
        "class":"高一一班",
        "name":"花月",
        "sex":"girl",
        "age":19,
        "height":"170",
        "weight":45
    });
    
    //保存对象
    huayue.save();
    
    console.log("光标挂起,我成功创建students这个表,并插入new实例里面的数据!");
    

    使用 node 运行这个程序。结果如下:


    node运行程序

    此时要在另一个 CMD 窗口输入 mongo 进入数据库的 REPL 环境。来查看数据是否插入成功。结果如下:


    查看输出结果

    上面还有一句代码未解释。现在来说明一下。

    {useNewUrlParser: true} 的作用?
    如果不加运行程序报如下的错。

     D:\mongodb\nodedb>node 1.js
    光标挂起,我成功创建students这个表,并插入new实例里面的数据!
    (node:3340) DeprecationWarning: current URL string parser is deprecated, and wil
    l be removed in a future version. To use the new parser, pass option { useNewUrl
    Parser: true } to MongoClient.connect.
    

    原因:https://mongoosejs.com/docs/deprecations.html

    二、创建模型Model和Schema

    为了之后可以使面向对象操作数据库,我们需要把 model 函数第二个参数提取出来,变成 schema ,schema 是系统内置的可以直接使用。模板如下:

    mongoose.model(类名字,schema)
    

    现在我们尝试把代码提出来。

    // 引入mongoose,mongoose的依赖中自动有mongodb的,所以不需要再次引入mongodb
    const mongoose = require("mongoose"); 
    
    //链接数据库,端口号不需要写,最后的反斜杠是数据库名字
    mongoose.connect("mongodb://localhost/dbs", {useNewUrlParser: true});
    
    //创建schema
    var schema = new mongoose.Schema({ 
        class:String,
        name : String,
        sex : String,
        age : Number,
        height:Number,
        weight:Number
    });
    var Student = mongoose.model("Student", schema);
    // 数据库状态监听
    // 连接成功
    mongoose.connection.on("connected", function () {    
        console.log("mongoose 数据库连接成功!");  
    });    
    
    // 连接异常
    mongoose.connection.on("error",function (err) {    
        console.log("Mongoose 数据库连接发现异常,异常为:" + err);  
    });    
     
    // 连接断开
    mongoose.connection.on("disconnected", function () {    
        console.log("Mongoose 数据库已经断开连接!");  
    });
    
    // 实例化对象其实就是往数据库里面增加东西
    var huayue = new Student({
        "class":"高一一班",
        "name":"花月",
        "sex":"girl",
        "age":19,
        "height":"170",
        "weight":45,
        "nationality":"满"
    });
    
    //保存对象另一种ES6的写法
    huayue.save().then(()=>console.log("光标挂起,我成功创建students这个表,并插入new实例里面的数据!"));
    
    三、mongoose 中的静态方法和动态方法

    Mongoose 最好用的地方就是可以提供静态方法和动态方法。
    动态方法和静态方法的区分:

    • 静态方法是类能够调用的方法:类名.方法()
    • 动态方法是实例能够调用的方法:实例.方法()

    接下来的案例演示,我们使用下面这个数据表:
    清空我们的 dbs 数据库,再把这个数据导入我们的 students 这个文档里面,使用命令为:

    mongoimport -d dbs -c students 1.txt
    

    回车显示:

    D:\mongodb\nodedb>mongoimport -d dbs -c students 1.txt
    2019-08-12T22:02:26.320+0800    connected to: localhost
    2019-08-12T22:02:26.376+0800    imported 22 documents
    

    本次案例演示的数据:

    {"class":"高一二班","name":"紫萱","sex":"girl","age":17,"hobby":["唱歌","看书","看剧"],"score":{"math":85,"philosophy":78,"english":98,"chemical":84}}
    {"class":"高一一班","name":"花月","sex":"girl","age":19,"hobby":["化妆","看剧","购物"],"score":{"math":77,"philosophy":89,"english":87,"chemical":58}}
    {"class":"高一三班","name":"佳宁","sex":"girl","age":20,"hobby":["看书","画画","跑步","游泳"],"score":{"math":94,"philosophy":89,"english":82,"chemical":98}}
    {"class":"高一一班","name":"香巧","sex":"girl","age":19,"hobby":["跳舞","游泳","化妆","看剧"],"score":{"math":93,"philosophy":86,"english":79,"chemical":85}}
    {"class":"高一一班","name":"惜玉","sex":"girl","age":17,"hobby":["摄影","跳舞","游泳"],"score":{"math":100,"philosophy":92,"english":91,"chemical":83}}
    {"class":"高一一班","name":"玥婷","sex":"girl","age":18,"hobby":["跳舞","游泳","做饭"],"score":{"math":89,"philosophy":90,"english":95,"chemical":80}}
    {"class":"高一四班","name":"诗琪","sex":"girl","age":19,"hobby":["唱歌","游泳","做饭","化妆"],"score":{"math":100,"philosophy":95,"english":77,"chemical":82}}
    {"class":"高一一班","name":"欣怡","sex":"girl","age":20,"hobby":["化妆","看剧","购物"],"score":{"math":99,"philosophy":68,"english":89,"chemical":98}}
    {"class":"高一一班","name":"玥怡","sex":"girl","age":19,"hobby":["唱歌","看书","看剧"],"score":{"math":89,"philosophy":69,"english":87,"chemical":84}}
    {"class":"高一四班","name":"梦瑶","sex":"girl","age":17,"hobby":["摄影","看剧","购物"],"score":{"math":78,"philosophy":79,"english":96,"chemical":85}}
    {"class":"高一一班","name":"怜雪","sex":"girl","age":19,"hobby":["唱歌","看书"],"score":{"math":88,"philosophy":89,"english":87,"chemical":85}}
    {"class":"高一二班","name":"安婷","sex":"girl","age":21,"hobby":["唱歌","跑步","摄影","跳舞"],"score":{"math":95,"philosophy":87,"english":92,"chemical":86}}
    {"class":"高一五班","name":"怡瑶","sex":"girl","age":20,"hobby":["游泳","做饭","化妆","看剧"],"score":{"math":92,"philosophy":81,"english":93,"chemical":89}}
    {"class":"高一一班","name":"韵茹","sex":"girl","age":16,"hobby":["吃饭","做饭","化妆","看剧"],"score":{"math":91,"philosophy":82,"english":95,"chemical":97}}
    {"class":"高一一班","name":"念蕾","sex":"girl","age":19,"hobby":["跑步","摄影","购物"],"score":{"math":99,"philosophy":90,"english":97,"chemical":88}}
    {"class":"高一五班","name":"一萌","sex":"girl","age":20,"hobby":["唱歌","看书","画画","购物"],"score":{"math":92,"philosophy":89,"english":73,"chemical":78}}
    {"class":"高一一班","name":"凌旋","sex":"girl","age":21,"hobby":["唱歌","做饭"],"score":{"math":99,"philosophy":79,"english":99,"chemical":88}}
    {"class":"高一二班","name":"芷梦","sex":"girl","age":22,"hobby":["化妆","看剧","购物"],"score":{"math":99,"philosophy":91,"english":92,"chemical":88}}
    {"class":"高一四班","name":"雅静","sex":"girl","age":16,"hobby":["跑步","摄影"],"score":{"math":76,"philosophy":88,"english":96,"chemical":100}}
    {"class":"高一一班","name":"紫夏","sex":"girl","age":15,"hobby":["跳舞","游泳","做饭"],"score":{"math":78,"philosophy":99,"english":92,"chemical":88}}
    {"class":"高一一班","name":"芸萱","sex":"girl","age":16,"hobby":["唱歌","游泳","做饭"],"score":{"math":89,"philosophy":75,"english":93,"chemical":90}}
    {"class":"高一五班","name":"靖瑶","sex":"girl","age":15,"hobby":["唱歌","看剧","购物"],"score":{"math":99,"philosophy":79,"english":96,"chemical":98}}
    

    数据对应的 schema:

    //创建schema
    var schema = new mongoose.Schema({ 
        class   : String,
        name    : String,
        sex     : String,
        age     : Number,
        hobby   : [String],
        score  : {math : Number , philosophy : Number , english : Number , chemical : Number}
    });
    

    静态方法要定义在 schema 上,定义完毕之后再 mongoose.model() 创建 model。
    静态方法中的 this 表示整个数据表,通常用于查询,this.find() 是非常常用的东西。
    下面定义一个静态方法,输入名字,控制台打印出这个人的全部信息。例如下面我输入花月。

    // 引入mongoose,mongoose的依赖中自动有mongodb的,所以不需要再次引入mongodb
    const mongoose = require("mongoose"); 
    
    //链接数据库,端口号不需要写,最后的反斜杠是数据库名字
    mongoose.connect("mongodb://localhost/dbs", {useNewUrlParser: true});
    
    //创建schema
    var schema = new mongoose.Schema({ 
        class   : String,
        name    : String,
        sex     : String,
        age     : Number,
        hobby   : [String],
        score  : {math : Number , philosophy : Number , english : Number , chemical : Number}
    });
    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    // 静态方法要定义在 schema 上,定义完毕之后再 mongoose.model() 创建 model。
    schema.statics.sayHello = function(name){
        // this就是这个表Model { Student }
        this.find({"name":name},function(err,res){
            console.log(res)
        });
    }
    // 创建这个 Student 这个类
    var Student = mongoose.model("Student", schema);
    // 调用静态方法
    Student.sayHello("花月");
    
    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    // 数据库状态监听
    // 连接成功
    mongoose.connection.on("connected", function () {    
        console.log("mongoose 数据库连接成功!");  
    }); 
    
    // 连接异常
    mongoose.connection.on("error",function (err) {    
        console.log("Mongoose 数据库连接发现异常,异常为:" + err);  
    });    
     
    // 连接断开
    mongoose.connection.on("disconnected", function () {    
        console.log("Mongoose 数据库已经断开连接!");  
    });
    

    node 运行控制台打印出结果如下:


    控制台检索结果

    我们检索出来结果是可以进行修改的。例如:

    现在我们查询的 花月 这个名字对应的性别是女孩。现在我们可以对她的性别进行更改。

    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    // 静态方法要定义在 schema 上,定义完毕之后再 mongoose.model() 创建 model。
    schema.statics.sayHello = function(name){
        // this就是这个表Model { Student }
        this.find({"name":name},function(err,res){
            var dom = res[0];
            if(dom.sex === "girl"){
                dom.sex = "boy";
                dom.save();
            }else {
                dom.sex = "girl";
            }
            console.log(dom);
        });
    }
    // 创建这个 Student 这个类
    var Student = mongoose.model("Student", schema);
    // 调用静态方法
    Student.sayHello("花月");
    
    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    

    使用 node 运行程序,运行结果如下:


    性别成功由女孩变成男孩

    运行完这个例子估计你也发现 mongoose 数据库的本质。就是可以使用面向对象的方法来操作数据库。这就是这个数据库最大的优点。

    现在来看动态方法,动态的方法也是定义在 schema 上。只是在调用的时候必须使用静态方法调用返回的实例(结果),只有返回的实例才能调用动态方法。这个绝技就叫做: 静包动

    我们来做一个例子来观察一下:

    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    // 静态方法要定义在 schema 上,定义完毕之后再 mongoose.model() 创建 model。
    schema.statics.sayHello = function(name){
        // this就是这个表Model { Student }
        this.find({"name":name},function(err,res){
            // 静态方法查询得到的实例来调用动态方法
            res[0].findName(name);
        });
    }
    // 动态方法也是定义在schema上
    schema.methods.findName = function(name){
        console.log("使用静包动,来查询" + name + "的个人信息");
    }
    // 创建这个 Student 这个类
    var Student = mongoose.model("Student", schema);
    // 调用静态方法
    Student.sayHello("花月");
    
    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    

    代码 node 运行结果:


    静包动查询花月
    四、封装动态方法

    上一节静态调用动态方法,过程不是太同步,我们来完善一下,调用静态的时候同时来调用动态方法。代码改装如下:

    // <<<<<<<<<<<<<<新增代码>>>>>>>>>>>>>>>>>>>>>>>>
    // 静态方法要定义在 schema 上,定义完毕之后再 mongoose.model() 创建 model。
    schema.statics.sayHello = function(name,callback){
        // this就是这个表Model { Student }
        this.find({"name":name},function(err,res){
            // 静态方法查询得到的实例来调用动态方法
            callback(res,name);
        });
    }
    // 动态方法也是定义在schema上
    schema.methods.findName = function(data,name){
        console.log("使用静包动,来查询" + name + "的个人信息");
        console.log("个人信息内容为:" + data);
    }
    // 创建这个 Student 这个类
    var Student = mongoose.model("Student", schema);
    // 调用静态方法
    Student.sayHello("花月",function(data,name){
        //静态方法返回的实例
        var el = data[0];
        el.findName(data,name);
    });
    
    通常动态方法和静态方法配合使用,能够让代码简洁
    五、案例练手

    下面的案例都是借用讲动态动态方法时候的 JSON 数据来练习。

    • 查找 hobby(爱好) 为 化妆 的人,并输出结果。
      查询的项为数组,可直接匹配。
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    schema.statics.findHobby = function(hobby,callback){
    
        this.find({"hobby":hobby},function(err,res){
            callback(res,hobby);
        });
    }
    schema.methods.printName = function(i,arr){
        arr.push(i["name"]);
    }
    
    var Student = mongoose.model("Student", schema);
    
    Student.findHobby("化妆",function(data,hobby){
        // 查询返回的结果是一个数组
        var arr = [];
        data.map(item => item.printName(item,arr));
        console.log("喜欢化妆的女孩有 : " + arr.join(","));
    });
    
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    

    node 运行结果:


    喜欢化妆的女孩
    • 寻找所有数学超过九十的人:查询项为对象,这个比较特殊,照理讲应该对象的 k 使用变量应该用方括号,这里不行必须使用 字符串打点调用的方法才行。代码如下:
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    schema.statics.findMath = function(score,callback){
    
        this.find({"score.math":{$gt:90}},function(err,res){
            callback(res,"math");
        });
    }
    schema.methods.printMath = function(i,arr){
        arr.push(i["name"]);
    }
    
    var Student = mongoose.model("Student", schema);
    
    Student.findMath("score",function(data){
        // 查询返回的结果是一个数组
        var arr = [];
        data.map(item => item.printMath(item,arr));
        console.log("数学超过九十的人有 : " + arr.join(","));
    });
    
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    

    node 运行结果如下:


    数学超过九十的人
    • 再来看数学过了九十,且年龄为十七的女孩。
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    schema.statics.findMath = function(score,callback){
    
        this.find({"score.math":{$gt:90},"age":18},function(err,res){
            callback(res,"math");
        });
    }
    schema.methods.printMath = function(i,arr){
        arr.push(i["name"]);
    }
    
    var Student = mongoose.model("Student", schema);
    
    Student.findMath("score",function(data){
        // 查询返回的结果是一个数组
        var arr = [];
        data.map(item => item.printMath(item,arr));
        console.log("数学过了九十,且年龄为十七的有 : " + arr.join(","));
    });
    
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    运行结果
    六、数据库的常见 API
    1. 查

    查询数据库 dbs 里面 students 文档里面的学生年纪小于 16 的人。并在控制台打印出来。

    // 引入mongoose,mongoose的依赖中自动有mongodb的,所以不需要再次引入mongodb
    const mongoose = require("mongoose"); 
    
    //链接数据库,端口号不需要写,最后的反斜杠是数据库名字
    mongoose.connect("mongodb://localhost/dbs", {useNewUrlParser: true});
    
    //第一步,创建一个schema
    var Student = mongoose.model("Student", { 
        class:String,
        name : String,
        sex : String,
        age : Number,
        height:Number,
        weight:Number
    });
    // 数据库状态监听
    // 连接成功
    mongoose.connection.on("connected", function () {    
        console.log("mongoose 数据库连接成功!");  
    });    
    
    // 连接异常
    mongoose.connection.on("error",function (err) {    
        console.log("Mongoose 数据库连接发现异常,异常为:" + err);  
    });    
     
    // 连接断开
    mongoose.connection.on("disconnected", function () {    
        console.log("Mongoose 数据库已经断开连接!");  
    });
    
    //以下是新增代码
    // 数据库查找年龄小于16的并打印出来
    Student.find({
        "age":{$lt:16}
    }).exec(function(err, res) {
        // exec表示执行res是查询的结果
        // if有错误扔出错误
        if (err) throw new Error("数据库查询错误:" + err)
        console.log(res);
    });
    

    node 运行程序。


    年龄小于16的人
    2. 统计数据库符合条件的个数

    Model.count :Counts number of matching documents in a database collection.
    更改代码部分:

    //...
    // 数据库查找年龄小于16的个数
    Student.count({"age":{$lt:16}},function(err, count) {
        // exec表示执行res是查询的结果
        // if有错误扔出错误
        if (err) throw new Error("数据库查询错误:" + err)
        console.log(`查询满足条件的个数为:${count}`);
    });
    

    查询结果为两个人。


    数据库查找年龄小于16的个数

    根据控制台的结果我们发现一个警告:

    (node:5028) DeprecationWarning: collection.count is deprecated, and will be remo
    ved in a future version. Use collection.countDocuments or collection.estimatedDo
    cumentCount instead
    

    node 提示我们 count 这个 API 已经被废弃,未来不会在使用了,请使用 countDocuments 或 estimatedDocumentCount 来替代。我们换一下就好了。

    接着讲 ,统计结果这个 API 有两个参数,第一个参数是一个 JSON 表示筛选条件,第二参数是一个函数,函数的第二个参数就是匹配成功的个数。如果把第一个参数省略的话就是查询整个表的内容:

    // 查询整个表的内容
    Student.countDocuments(function(err, count) {
        // exec表示执行res是查询的结果
        // if有错误扔出错误
        if (err) throw new Error("数据库查询错误:" + err)
        console.log(`查询满足条件的个数为:${count}`);
    });
    

    node 运行查询结果显示如下:


    查询整个表的内容
    3. 对查询结果排序

    我们现在查询年龄在 16 到 19 之间的人,一共是四个。查询结果如下:


    年龄在 16 到 19 之间的人

    现在我们根据查询结果对她们的化学成绩(chemical)进行排序:

    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    var Student = mongoose.model("Student", schema);
    
    Student.find({"age":{$lt:19,$gt:16}}).sort({"score.chemical":1}).exec(function(err,res){
        console.log(res);
    });
    // 设置排序的时候:
    
    // 如果传入的参数是个对象,字段值可以是 asc(正序)或 1, desc(倒叙) 或 -1
    
    // 如果传入参数是字符串,它得是以空格间隔的字段路径名列表。
    // 每个字段的排列顺序默认是正序,如果字段名有 - 前缀, 那么这个字段是倒序。
    
    // 示例sort("age -id -score.math")  年龄字段正向排序...另外两个倒叙
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    

    node 查询结果为:


    正序排列
    4. exec(err,res)表示执行查询结果,res 是以数组的形式来存取查询的结果。
    5. skip指定对查询结果跳过的文档条数。

    我们现在已知年龄在 16 到 19 之间的人,一共是四个。现在我们跳过两个显示。

    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    var Student = mongoose.model("Student", schema);
    
    Student.find({"age":{$lt:19,$gt:16}}).skip(2).exec(function(err,res){
        console.log(res);
    });
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    skip(2)
    6. limit 指定查询结果的最大条数。

    limit 就是自定查询结果显示条数的。
    我们现在已知年龄在 16 到 19 之间的人,一共是四个。我们现在只想显示一个。代码如下:

    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    
    var Student = mongoose.model("Student", schema);
    
    Student.find({"age":{$lt:19,$gt:16}}).limit(1).exec(function(err,res){
        console.log(res);
    });
    // <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>
    

    node 运行结果:


    limit(1) 只显示一条

    学习更多请参考:
    Mongoose 5.0 中文文档

    相关文章

      网友评论

        本文标题:mongoose 入门指引

        本文链接:https://www.haomeiwen.com/subject/kvkzdctx.html