Mongodb 以及 node.js中使用mongoose操作数据库

Posted luckest

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mongodb 以及 node.js中使用mongoose操作数据库相关的知识,希望对你有一定的参考价值。

Mongodb 以及 node.js中使用mongoose操作数据库

1、lowdb

一个简陋的数据库第三方库,使用JSON文件来保存数据,进行增删改查。

在没有数据库或者数据量小到不使用数据库的时候可以使用,了解即可。

2、Mongodb是什么?

MongoDB是一个基于分布式文件存储的数据库。

相比于纯文件管理数据,数据库管理数据有如下的特点:

  • 速度更快
  • 扩展性更强
  • 安全性更强

为什么选择Mongodb,因为它的操作语法与JS类似,容易上手,学习成本低。

3、Mongodb核心概念

  • 数据库(database)数据库就是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存放很多集合。
  • 集合(collecttion)集合类似于JS中的数组,在集合中可以存放很多文档。
  • 文档(document)文档是数据库中的最小单位,类似JS中的对象。

4、Mongodb的下载与使用

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

建议选择zip类型,通用性更强。

配置步骤如下:

  • 将压缩包移动到C:\\Program Files下,然后解压
  • 创建C:\\data\\db目录,mongodb会将数据存在这里
  • 以mongodb中的bin目录作为工作目录,启动命令行。
  • 运行mongod.exe

看到waiting for connections就表明服务启动成功。

客户端程序

  • 运行mongo.exe

注意:

  • 为了后续方便使用mongod命令,可以将bin目录配置到环境变量path中
  • 千万不要选中服务端窗口的内容,选中会停止服务,可以敲回车取消选中

5、数据库与集合命令

5.1、数据库命令

  • 1、显示所有数据库
    • show dbs
  • 2、切换到指定数据库
    • use 数据库名
  • 3、显示当前所在的数据库
    • db
  • 4、删除当前数据库
    • use 库名
    • db.dropDatabase()

5.2、集合命令

  • 1、创建集合
    • db.createCollection(\'集合名称\')
  • 2、显示当前数据库中的所有集合
    • show collections
  • 3、删除某个集合
    • db.集合名.drop()
  • 4、重命名集合
    • db.集合名.renameCollection(\'newName\')

5.3、文档命令

  • 1、插入文档
    • db.集合名.insert(文档对象)
  • 2、查询文档
    • db.集合名.find(age: 20) // 找年龄是20的文档,find不传参数,查询全部文档
  • 3、更新文档
    • db.集合名.update(查询条件,新的文档) // 不用$set,会替换掉整个文档
    • db.集合名.update(name: \'张三\', $set:age:19) // 如果用$set,只修改age
  • 4、删除文档
    • db.集合名.remove(查询条件)

6、Mongoose

Mongoose是一个对象文档模型库。

方便我们使用代码去操作mongodb数据库。

npm i mongoose@6

// 导入mongoose
const mongoose = require(\'mongoose\');

// 连接mongoose服务
mongoose.connect(\'mongodb://127.0.0.1:27017/bilibili\'); // 如果bilibili数据库不存在会自动创建

// 设置回调
mongoose.connection.on(\'open\', () => 
    console.log(\'连接成功\');
); // 连接成功回调
mongoose.connection.on(\'error\', () => 
    console.log(\'连接失败\');
); // 连接失败回调
mongoose.connection.on(\'close\', () => 
    console.log(\'连接关闭\');
); // 连接关闭回调

// 关闭mongodb的连接
setTimeout(() => 
    mongoose.disconnect();
, 3000);

6.1、插入文档

// 导入mongoose
const mongoose = require(\'mongoose\');

// 连接mongoose服务
mongoose.connect(\'mongodb://127.0.0.1:27017/bilibili\'); // 如果bilibili数据库不存在会自动创建

// 设置回调
mongoose.connection.on(\'open\', () => 
    // 创建文档的结构对象,设置集合中文档的属性以及属性值的类型
    let BookSchema = new mongoose.Schema(
        name: String,
        author: String,
        price: Number
    );

    // 创建模型对象,对文档操作的封装对象
    let BookModel = mongoose.model(\'book\', BookSchema);

    // 新增
    // BookModel.create(
    //     name: \'西游记\',
    //     author: \'吴承恩\',
    //     price: 19.9
    // , (err,data) => 
    //     if (err) 
    //         console.log(err);
    //         return;
    //     
    //     // 如果没出错,则输出插入后的文档对象
    //     console.log(data);
    // );

    // 新增多条
    BookModel.insertMany([
        name: \'西游记\',
        author: \'吴承恩\',
        price: 19.9
    ,
        name: \'西游记\',
        author: \'吴承恩\',
        price: 19.9
    ,
        name: \'西游记\',
        author: \'吴承恩\',
        price: 19.9
    ], (err,data) => 
        if (err) 
            console.log(err);
            return;
        
        // 如果没出错,则输出插入后的文档对象
        console.log(data);
    );
); // 连接成功回调
mongoose.connection.on(\'error\', () => 
    console.log(\'连接失败\');
); // 连接失败回调
mongoose.connection.on(\'close\', () => 
    console.log(\'连接关闭\');
); // 连接关闭回调

6.2、字段类型

String:字符串

Number:数字

Boolean:布尔值

Array:数组

Date:日期

Buffer:Buffer对象

Mixed:任意类型,需要使用mongoose.Schema.Types.Mixed指定

ObjectId:对象ID,需要使用mongoose.Schema.Types.ObjectId指定

Decimal128:高精度数字,需要使用mongoose.Schema.Types.Decimal128指定

6.3、字段值验证

6.3.1、必填项

title: 
  type: String,
  required: true

6.3.2、默认值

author: 
  type: String,
  default: \'匿名\'

6.3.3、枚举值

sex: 
  type: String,
  enum: [\'男\', \'女\']

6.3.4、唯一值

username: 
  type: String,
  unique: true,

unique需要重建集合才有效果。永远不要相信用户的输入。

6.4、删除文档

// 导入mongoose
const mongoose = require(\'mongoose\');

// 连接mongoose服务
mongoose.connect(\'mongodb://127.0.0.1:27017/bilibili\'); // 如果bilibili数据库不存在会自动创建

// 设置回调
mongoose.connection.on(\'open\', () => 
    // 创建文档的结构对象,设置集合中文档的属性以及属性值的类型
    let BookSchema = new mongoose.Schema(
        name: String,
        author: String,
        price: Number
    );

    // 创建模型对象,对文档操作的封装对象
    let BookModel = mongoose.model(\'book\', BookSchema);

    // 删除一条
    BookModel.deleteOne(_id: \'6461be48670777b4e3f2bfcc\', (err, data) => 
        if (err) 
            console.log(err);
            return;
        
        console.log(data);
    );
    // 批量删除
    BookModel.deleteMany(is_hot: false, (err, data) => 
        if (err) 
            console.log(err);
            return;
        
        console.log(data);
    );

); // 连接成功回调
mongoose.connection.on(\'error\', () => 
    console.log(\'连接失败\');
); // 连接失败回调
mongoose.connection.on(\'close\', () => 
    console.log(\'连接关闭\');
); // 连接关闭回调

6.5、更新文档

// 导入mongoose
const mongoose = require(\'mongoose\');

// 连接mongoose服务
mongoose.connect(\'mongodb://127.0.0.1:27017/bilibili\'); // 如果bilibili数据库不存在会自动创建

// 设置回调
mongoose.connection.on(\'open\', () => 
    // 创建文档的结构对象,设置集合中文档的属性以及属性值的类型
    let BookSchema = new mongoose.Schema(
        name: String,
        author: String,
        price: Number
    );

    // 创建模型对象,对文档操作的封装对象
    let BookModel = mongoose.model(\'book\', BookSchema);

    // 更新一条
    // BookModel.updateOne(name: \'西游记\', price: 9.9, (err,data) => 
    //     // 判断err
    //     if (err) 
    //         console.log(\'更新失败\');
    //         return;
    //     
    //     console.log(data);
    // );

    // 批量更新
    BookModel.updateMany(name: \'西游记\', price: 9.9, (err,data) => 
        // 判断err
        if (err) 
            console.log(\'更新失败\');
            return;
        
        console.log(data);
    );

); // 连接成功回调
mongoose.connection.on(\'error\', () => 
    console.log(\'连接失败\');
); // 连接失败回调
mongoose.connection.on(\'close\', () => 
    console.log(\'连接关闭\');
); // 连接关闭回调

6.6、查询文档

// 导入mongoose
const mongoose = require(\'mongoose\');

// 连接mongoose服务
mongoose.connect(\'mongodb://127.0.0.1:27017/bilibili\'); // 如果bilibili数据库不存在会自动创建

// 设置回调
mongoose.connection.on(\'open\', () => 
    // 创建文档的结构对象,设置集合中文档的属性以及属性值的类型
    let BookSchema = new mongoose.Schema(
        name: String,
        author: String,
        price: Number
    );

    // 创建模型对象,对文档操作的封装对象
    let BookModel = mongoose.model(\'book\', BookSchema);

    // 查询单条
    BookModel.findOne(name: \'西游记\', (err, data) => 
        if (err) 
            console.log(err);
            return;
        
        console.log(data);
    );

    // 根据ID获取文档
    BookModel.findById(\'6461c222f73d78ca0b9fd980\', (err, data) => 
        if (err) 
            console.log(err);
            return;
        
        console.log(data);
    );

    // 批量获取(有条件)
    BookModel.find(author: \'吴承恩\', (err, data) => 
        if (err) 
            console.log(err);
            return;
        
        console.log(data);
    );

    // 无条件,读取所有
    BookModel.find((err, data) => 
        if (err) 
            console.log(err);
            return;
        
        console.log(data);
    );

); // 连接成功回调
mongoose.connection.on(\'error\', () => 
    console.log(\'连接失败\');
); // 连接失败回调
mongoose.connection.on(\'close\', () => 
    console.log(\'连接关闭\');
); // 连接关闭回调

6.7、条件控制

6.7.1、运算符

在mongodb中,不能用><等运算符,要使用替代符号:

  • >,$gt
  • <,$lt
  • >=,$gte
  • <\\,$lte
  • !==,$ne
db.students.find(id:$gt:3); id号比3大的所有文档

6.7.2、逻辑运算

$or逻辑或的情况

db.students.find($or:[age:18, age:24]);

$and逻辑与的情况

db.students.find($and:[age:18, age:24]);

6.7.3、正则匹配

条件中可以直接使用JS的正则语法,可以进行模糊查询:

db.students.find(name:/imissyou/);

6.8、mongoose个性化读取

6.7.1、字段筛选

SongModel.find().select(_id:0, title:1).exec(function(err, data) 
  if (err) throw err;
  console.log(data);
  mongoose.connection.close();
)

6.7.2、数据排序

SongModel.find().sort(hot:1).exec(function(err, data) 
  if (err) throw err;
  console.log(data);
  mongoose.connection.close();
)

6.7.3、数据截取

// skip跳过,limit限定
SongModel.find().skip(10).limit(10).exec(function(err, data) 
  if (err) throw err;
  console.log(data);
  mongoose.connection.close();
)

7、mongodb图形化管理工具

7.1、robo3t

去github上下载,免费

7.2、Navicat

收费

将js进行到底:node学习8

Node.js数据库篇——MongoDB

废话:现代web开发可以说完全是数据库驱动的,而对于我这样的PHP程序员来说,对Mysql向来十分钟情,MongoDB的兴起让我不能再对Mysql孤注一掷,《了不起的node.js》一书中首推的数据库就是MongoDB,也许其性能和功能并没有Mysql那么强大,靠山也没有oracle这样的大公司,但是为什么我觉得值得去研究和使用,在这之前,我们先来说说MongoDB好处都有啥!

MongoDB

首先,MongoDB非常的年轻,生于2012年,然后他是一个基于分布式文件存储的数据库。他非常适合Node.js应用。

MongoDB的定位介于关系型数据库和非关系型数据库,支持的数据结构松散,类似于json。

和Mysql最大的区别是:mysql需要按照固定的表结构存储数据,而mongo可以将任意类型的文档数据存储在集合中。

当MongoDB与Node.js强强联手时,基本存储格式都是json,因此数据库——后端——前端的数据格式可以得到较好统一,这是最骚的!我觉得json真的是我最爱的web数据传输格式。

最后,MongoDB虽然不是完整的关系型数据库,但依然强于NoSQL类型数据库,因为他并非简单的键值对存储,而是可以多层次(就是类似json),对象下还可以存储对象,这就使得他可以存储较为复杂的数据结构和关系,所以这真的就牛逼了。

至于性能,自行研究,参考:https://www.cnblogs.com/web-fusheng/p/6884759.html

Windows下安装MongoDB

别说安装一步到位,我在windows下安装还真遇到一些小坑。

首先官方下载地址:https://www.mongodb.com/download-center#community

我下载的是社区版本,一般个人就使用社区版就行了,之前oracle学习我也使用社区版的。

安装选择custom模式,安装目录下有个bin目录,将其添加到环境变量中

打开cmd,安装mongoDB服务,注意这一点很关键,直接启动Mongo是不行的,另外尽量用管理员身份运行cmd去做以下操作

mongod --dbpath D:\\Programs\\MongoDB\\Server\\3.6\\db --logpath D:\\Programs\\MongoDB\\Server\\3.6\\log\\mongodb.log --install --serviceName "mongo"

这段命令做了两件事,一件事是设置了数据文件目录和日志文件(oracle会在安装时选择好),另一件就是把Mongo的服务加入到windows的net服务中去。

接下来:

net start mongo

看到服务启动成功即可,如果不成功,切换为管理员权限。

连接MongoDB:

mongo

Node.js连接MongoDB

任何一门语言需要连接到数据库,就需要数据库的API,以此提供驱动库,使用前导入驱动库即可调用API,数据库驱动的作用就是使得语言理解数据库连接协议,负责解码编码与数据库交换的数据,保证连接的稳定性等。

在Node.js中使用mongo需要mongodb模块支持

package.json

{
    "name":"user-login-example",
    "description":"a user login,register example by using mongoDB",
    "version":"0.0.1",
    "dependencies":{
        "express":"latest",
        "mongodb":"latest",
        "jade":"latest",
        "express-session":"latest"
    }
}

连接插入测试:

var mongo = require("mongodb").MongoClient;

//连接到mongo服务
mongo.connect(\'mongodb://localhost:27017\',function(err,client){
    if(err) throw err;
    console.log("Connected mongo");
    //选择test库
    db = client.db("test");

	//从test中选择documents这个集合
    var collection = db.collection(\'documents\');
    var data = [{a:1},{a:2},{a:3}];
    //插入多条数据
    collection.insertMany(data,function(err,res){
        if(err) throw err;
        else console.log("3 documents inserted");
        client.close();
    });
});
node server

运行之后使用mongo compass查看数据库里多的数据

可以看到三条数据已经插入其中

这里写图片描述

注意:在使用MongoDB API连接后,不存在的数据库会在操作前创建,不存在集合(collection)会在操作前创建,mango不必担心数据库是否存在的问题。collection类似于mysql下的一张表。

这个API可以使用insertMany一次插入多条数据,让我觉得十分惊奇!

实战——开发登陆注册样例

下面进入简单的实践环节,使用node.js和mongoDB开发用户注册登陆界面,具体需求:

  1. 用户进入登陆界面登陆
  2. 用户注册用户
  3. 用户登陆成功进入个人主页

需要用jade模块构建视图模型,express的session中间件,mongo数据库存储用户注册信息。

除此以外,是时候介绍以下模块化思想了:
在web开发中,不可能把所有请求和控制器处理都放在同一个js文件中,应该要为每一个view提供一个controller,这是MVC模式的一种思想,也就是不同页面处理应当有单独的文件管理,便于后期维护,减少server.js文件代码量,不管怎么说专门的分类看着都让人爽呐。

需要利用当初学习node第一章时的exports对象,将模块API暴露给其他模块使用,实现模块划分。

项目文件

这里写图片描述

views目录

这里写图片描述

项目文件构建基本思想是将视图和控制器分离,控制器模块化,每一个模块对应一个视图文件Jade,构建思想来源于我之前PHP MVC开发经验。

server.js

var app = require("express")();
var bodyParser = require(\'body-parser\');
var cookieParser = require(\'cookie-parser\');
var session = require("express-session");

//引入控制器
var index = require("./index"),
    login = require("./login"),
    register = require("./register");

app.use(bodyParser.json()); // for parsing application/json
app.use(cookieParser("devilyouwei"));
app.use(bodyParser.urlencoded({ extended: true })); //对post请求表单提交的数据编码,否则服务器端无法获得

//使用session中间件
app.use(session({
  secret: \'devilyouwei\',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: false ,maxAge:3600000}   //注意secure必须是false,否则session无法存储
}));

app.set("view engine","jade");
app.set("views",__dirname+"/views");

app.get("/",index);
app.get("/login",login);
app.get("/register",register);
app.get("/logout",index.logout);

//表单提交请求
app.post("/login",login);
app.post("/register",register);
app.listen(3000);

这是主模块,提供http服务,并将请求分配到不同的js控制器上

index.js

module.exports=index;
function index(req,res,next){
    console.log(req.session);
    if(req.session.user)
        res.render("index",{authenticated:true,username:req.session.user});
    else
        res.render("index");
}
index.logout = function(req,res,next){
    req.session.user = null;
    res.redirect("/");
}

主页控制,需检查session

login.js

module.exports = login;
var mongo = require("mongodb").MongoClient;
function login(req,res,next){
    if(req.method == "GET")
        res.render("login");
    else if(req.method == "POST"){
        auth(req.body,function(flag){
            //通过验证,账号密码正确
            if(flag){
                req.session.user = flag.email;
                req.session.cookie.expires = new Date(Date.now() + 3600000);
                req.session.cookie.maxAge = 3600000;
                console.log(req.session);
                res.redirect("/");
            }else{
                //账号密码错误
                res.send("账号密码错误!")
            }
        });
    }else{
        res.send(404);
    }
}
function auth(data,fn){
    mongo.connect(\'mongodb://localhost:27017\',function(err,client){
        if(err) throw err;

        db = client.db("test");

        var collection = db.collection(\'users\');
        collection.find(data).toArray(function(err,docs){
            if(err) throw err;
            client.close();
            //如果没找到,数组长度为0,返回false,表示账号密码有错误
            if(docs.length==0) fn(false);
            else fn(docs[0]);
        });
    })
}

登陆模块,auth方法用于查询mangodb匹配账号密码

特别注意:在login.js中我们使用了session,这是在引入了express-session模块后用户每次请求的request对象都会带有session元素,但是记得如果是http请求(非https)必须在server.js设置关闭cookie的secure(笔者一开始没在意这个配置,发现保存不了session以为是node.js有毛病呢),并记得在设置session的同时设置cookie的时间长度,避免丢失。

register.js

module.exports = register

var mongo = require("mongodb").MongoClient;

function register(req,res,next){
    if(req.method == "GET")
        res.render("register");
    else if(req.method == "POST"){
        //此处需要做安全验证,略
        save(req.body,function(){
            res.redirect("/login");
        });
    }else{
        res.send(404);
    }
}

//保存用户注册信息
function save(data,fn){
    mongo.connect(\'mongodb://localhost:27017\',function(err,client){
        if(err) throw err;
        console.log("Connected mongo");

        db = client.db("test");

        var collection = db.collection(\'users\');
        collection.insertMany([data],function(err,res){
            if(err) throw err;
            else console.log("1 user inserted");
            client.close();
            fn();
        });
    })
}

注册模块,save方法对mongodb进行写入操作

下面介绍以下mongodb模块连接和操作mongodb的基本套路:

  • require进来mongodb模块,并获得MongoClient对象
  • 使用connect方法按照套接字连接(默认套接字是mongodb://localhost:27017)
  • 回调函数中第二个参数使用db方法选择数据库
  • 数据库对象选择相应的collection(集合,也就相当于关系型数据库中的表)
  • 使用insertMany数组插入多行数据
  • 使用find方法匹配数据,这里并没有用到主键这种东西

代码不全部列出,jade文件代码不是重点,故不一一列出,样例完整代码下载地址:
http://download.csdn.net/download/u014466109/10251935

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

以上是关于Mongodb 以及 node.js中使用mongoose操作数据库的主要内容,如果未能解决你的问题,请参考以下文章

将js进行到底:node学习8

Mongodb 以及 node.js中使用mongoose操作数据库

ReferenceError:TextEncoder 没有用猫鼬定义 Node.js

通过 Heroku 部署时,本地 MongoDB 将无法连接

重学Node.js 第3篇mongodb以及mongoose的使用

为啥这个 Node.js 插件 Mongoose 不起作用?我遵循了所有指示