基础前端

mongoose 入门指引

2019-08-14  本文已影响1人  CondorHero
一、快速入门

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 数据来练习。

// <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>

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 运行结果:


喜欢化妆的女孩
// <<<<<<<<<<<<<<项目代码>>>>>>>>>>>>>>>>>>>>>>>>

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 中文文档

上一篇下一篇

猜你喜欢

热点阅读