Node操作MongoDB数据库

原文链接:http://www.xingxin.me/

Web应用离不开数据库的操作,我们将陆续了解Node操作MongoDBMySQL这是两个具有代表性的数据库,非关系型数据库(NoSQL)及关系型数据库(SQL)。这一节,我们主要了解node中使用MongoDB,并与express结合实现一个简单图书管理小应用

我们来简单看看关系型数据库与非关系型数据库

非关系型数据库-NoSQL

在NoSQL之前,数据库中SQL一支独秀。随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,访问量巨大,传统关系型数据库遇到各种瓶颈(如:高并发读写需求,高扩展性和可用性,复杂SQL,特别是多表关联查询等等)。NoSQL就诞生于此背景下,NoSQL数据库的出现,弥补了关系数据(比如MySQL)在某些方面的不足,在某些方面能极大的节省开发成本和维护成本

NoSQL的优势

  • 易扩展
  • 高性能
  • 灵活的数据模型
  • 高可用

NoSQL的分类

NoSQL可以大体上分为4个种类:Key-value、Document-Oriented、Column-Family Databases以及 Graph-Oriented Databases

类型 代表 特点
键值(Key-Value) MemcacheDB 键值数据库就像在传统语言中使用的哈希表。你可以通过key来添加、查询或者删除数据,鉴于使用主键访问,所以会获得不错的性能及扩展性。
面向文档(Document-Oriented) MongoDB 文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有有机会对某些字段建立索引,实现关系数据库的某些功能。
列存储(Wide Column Store/Column-Family) Cassandra 顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。
图(Graph-Oriented) Neo4J 图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。

关系型数据库-SQL

SQL指结构化查询语言,全称是 Structured Query Language,关系数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据,关简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织

SQL的优点

  • 容易理解:二维表结构是非常贴近逻辑世界的一个概念,关系模型相对网状、层次等其他模型来说更容易理解
  • 使用方便:通用的SQL语言使得操作关系型数据库非常方便
  • 易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率

前文提到了SQL遇到了瓶颈,并不是说SQL不行(个人认为MySQL是业内相当优秀的数据库),只是应用场景的不同

RDBMS 数据库程序

RDBMS 指关系型数据库管理系统(Relational Database Management System)。RDBMS 是 SQL 的基础,同样也是所有现代数据库系统的基础,比如 MS SQL Server、IBM DB2、Oracle、MySQL 以及 Microsoft Access。RDBMS 中的数据存储在被称为表的数据库对象中。表是相关的数据项的集合,它由列和行组成

接下来我们就一起来使用Node操作MongoDB(Node操作MySQL将在下一篇介绍),并使用它来写一个建议的图书管理小案例

Node操作MongoDB

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。下面这个表就展示出来MongoDB与SQL数据库的一个简单比较

SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins   表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键

MongoDB和Node.js特别配,因为MongoDB是基于文档的,文档是按BSON(JSON的轻量化二进制格式)存储的,增删改查等管理数据库的命令和JavaScript语法很像,这里我们选择mongoose来进行增删改查,mongoose构建在MongoDB之上,提供了Schema、Model和Document对象,用起来很方便

1. 安装Mongoose

$ npm install mongoose

安装好后 require('mongoose')就可以使用了

2.使用Mongoose进行CRUD

连接数据库

const mongoose = require("mongoose")
// 使用原生promise,mongoose自带promise不再支持了
mongoose.Promise = global.Promise const db=mongoose.connect('mongodb://localhost/test') db.connection.on("error", function (error) {
console.log("数据库连接失败:" + error)
}) db.connection.on("open", function () {
console.log("数据库连接成功")
})

我们来看看Mongoose的几个名词

  • Schema : 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
  • Model : 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
  • Entity : 由Model创建的实体,他的操作也会影响数据库

Schema生成ModelModel创造EntityModelEntity都可对数据库操作造成影响,但ModelEntity更具操作性

关于mongoose最重要的就是理解Schema Model Entity ,它的各种方法直接去查文档使用就好。

Schema

schema是mongoose里会用到的一种数据模式,可以理解为表结构的定义;每个schema会映射到mongodb中的一个collection,它不具备操作数据库的能力

const kittySchema = mongoose.Schema({
name: String
})

Schema.Type

Schema.Type是由Mongoose内定的一些数据类型,基本数据类型都在其中,他也内置了一些Mongoose特有的Schema.Type。当然,你也可以自定义Schema.Type,只有满足Schema.Type的类型才能定义在Schema

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • Objectid
  • Array

Model

定义好了Schema,接下就是生成Model。
model是由schema生成的模型,可以对数据库的操作

var Kitten = mongoose.model('Kitten', kittySchema)

Entity
用Model创建Entity,Entity可以对数据库操作

var silence = new Kitten({ name: 'Silence' })
console.log(silence.name); // 'Silence'

查询

model.find({},field,callback) // 参数1忽略,或为空对象则返回所有集合文档

model.find({},{'name':1, 'age':0},callback) //过滤查询,参数2: {'name':1, 'age':0} 查询文档的返回结果包含name , 不包含age.(_id默认是1)

model.find({},null,{limit:20}) // 游标操作 limit 限制返回结果数量为20个,如不足20个则返回所有

model.findOne({}, callback) // 查询找到的第一个文档

model.findById('obj._id', callback) // 查询找到的第一个文档, 只接受 _id 的值查询

创建

// 在集合中创建一个文档
Model.create(doc(s), [callback]) Entity.save(callback)

删除

Model.remove([criteria], [callback]) // 根据条件查找到并删除

Model.findByIdAndRemove(id, [options], [callback]) // 根据id查找到并删除

修改

Model.update(conditions, update, [options], [callback]) // 根据参数找到并更新

Model.findByIdAndUpdate(id, [update], [options], [callback])  // 根据id查找到并更新

上面简单写了几个常用操作,关于Mongoose的更多使用请移步官网 ,我就不搬了 (推荐阅读: Mongoose学习参考文档——基础篇)

图书管理系统

了解了MongoDB以及Mongoose的简单使用,我们一起来实现一个图书管理的小案例,其有最基本的增删改查,同时我们将了解到express的基本使用,同时会认识下模板引擎,但这些只是简略了解,这节的重点是Mongoose操作MongoDB

UI采用了漂亮的UIkit3

传送门: Github

可以去github拉下来,然后npm install 然后node index.js即可跑起来

1. 准备工作

我们先随便新建一个文件夹,然后在这个目录下

$ npm init

初始化项目完成后使用下载express,mongoose,nunjucks(模板引擎), body-parser(bodyParser中间件用来解析http请求体)

$ npm install express mongoose nunjucks body-parser --save

接下来我们新建index.js文件,在里面将express跑起来

const express = require('express')
const nunjucks = require('nunjucks')
const path = require('path')
const bodyParser = require('body-parser')
const app = express() // 静态文件目录
app.use(express.static(path.join(__dirname, 'public'))) // 配置模板引擎
nunjucks.configure(path.join(__dirname, 'views'), {
autoescape: true,
express: app
})
app.set('view engine', 'html')
// 配置bodyParser
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false})) // 路由
app.get('/', (req, res)=>{
res.send('HELLO mongo')
}) const server = app.listen(3000, function () {
console.log('app listening at http:localhost:3000')
})

现在我们执行node index.js 便可以跑起来了,当然更推荐使用以前介绍到的supervisor

这里我们再聊一聊Node web应用的模板引擎,这儿我们用了nunjucks 这是mozilla维护的一个模板引擎,他是 jinja2的javascript版本,用过python的jinja2一定会感觉很亲切,除此之外,很有很多有些的模板引擎如ejsjade。但个人认为jade是反人类的,因此更推荐Nunjucks及ejs。当然了,这取决于大家的喜好,更多模板引擎请自行搜索了解。

我们新建一个views文件夹,放置模板。这儿只需要一个主页显示所有图书index.html,add.html添加图书,edit.html编辑图书,base.html作为基础模板,其他模板文件可以继承它

关于nunjucks,我们以他官网的那一段小代码来简单看一下

{% extends "base.html" %} {# 继承base.html 这是注释 #}

{# 区块 #}
{% block header %}
<h1>{{ title }}</h1>
{% endblock %} {% block content %}
<ul>
{# 循环 #}
{% for name, item in items %}
<li>{{ name }}: {{ item }}</li>
{% endfor %}
</ul>
{% endblock %}

更多使用请自行查看官网

2. 功能设计以及路由配置

这儿我们就来看看,这个小的图书管理系统需要的功能。增删改查 就是新增图书,删除图书,修改图书,显示所有图书

我们就可以根据这几个功能来配置我们的路由了

const express = require('express')
const router = express.Router() // GET 首页显示全部书籍
router.get('/', (req, res) => { }) // GET 新增书籍
router.get('/add', (req, res) => { })
// POST 新增书籍
router.post('/add', (req, res) => { }) // GET 删除
router.get('/:bookId/remove', (req, res) => { })
// GET 编辑
router.get('/:bookId/edit', (req, res) => { }) // POST 编辑
router.post('/:bookId/edit', (req, res) => { })

这儿为了项目结构更清晰,我们不把路由写在index.js中,而是提取到routes目录下,我们新建routes目录,在下面新建book.js ,然后将相关路由全部放到其中并导出,

const express = require('express')
const router = express.Router() ···
···
··· module.exports = router // 导出

然后新建一个index.js文件

module.exports = function (app) {
app.use('/', require('./book'))
}

这儿这样划分,在这可能看不出太多优势,但是在大一点的应用中,我们这样配置可以让功能划分很清晰。

最后我们在入口文件index.js中将路由require进去,就可以使用了,

···
routes(app)
···

到此,前置工作就差不多了,下面我们就可以进入今天的重头戏Mongoose

3. 功能实现, Mongoose操作MongoDB

新建lib文件夹,新建mongo.js文件,连接数据库,在其中定义 Schema 并发布为model

const mongoose = require('mongoose')
const Schema = mongoose.Schema mongoose.Promise = global.Promise // MongoDB会自动建立books数据库
const db = mongoose.connect('mongodb://localhost:27017/books') db.connection.on("error", function (error) {
console.log("数据库连接失败:" + error)
}) db.connection.on("open", function () {
console.log("数据库连接成功")
}) const BookSchema = Schema({
title: {
unique: true, // 唯一的不可重复
type: 'String', // Schema.Type String类型
},
summary: 'String',
price: 'Number',
meta: {
createAt: {
type: Date,
default: Date.now()
}
}
}) exports.Book = mongoose.model('Book', BookSchema)

新建Models文件夹,在其中新建books.js放置对MongoDB 的一些操作,这里面使用了promise,如果还不会那你就得去补补了

const Book = require('../lib/mongo').Book

module.exports = {
getBooks(){
return Book
.find({})
.sort({_id: -})
.exec()
},
getBook(id){
return Book
.findById(id)
.exec()
},
editBook(id, data){
return Book
.findByIdAndUpdate(id, data)
.exec()
},
addBook(book){
return Book.create(book)
},
delBook(id){
return Book
.findByIdAndRemove(id)
.exec()
}
}

这里面的一些方法,我们在前面讲Mongoose的时候都了解过了,想了解的更多还是推荐去官网看看

最后我们就是根据不同的路由进行不同的处理了

const express = require('express')
const router = express.Router()
const BookModel = require('../models/books') router.get('/', (req, res) => {
BookModel.getBooks()
.then((books) => {
res.render('index', {books})
})
}) router.get('/add', (req, res) => {
res.render('add')
}) router.post('/add', (req, res) => {
let book = req.body
BookModel.addBook(book)
.then((result) => {
res.redirect('/')
})
}) router.get('/:bookId/remove', (req, res) => {
BookModel.delBook(req.params.bookId)
.then((book) => {
res.redirect('/')
})
}) router.get('/:bookId/edit', (req, res) => {
let book = req.body
BookModel.getBook(req.params.bookId)
.then((book) => {
res.render('edit', {
book,
bookid: req.params.bookId
})
})
}) router.post('/:bookId/edit', (req, res) => {
let book = req.body
BookModel.editBook(req.params.bookId, book)
.then((result)=>{
res.redirect('/')
})
}) module.exports = router

OK!!!到此,我们这小项目基本就算完成了。代码详见GitHub 作为一个学习案例,这算完成了,但其中可以优化完善的地方还很多,大家可以自行探索···

抛砖引玉

相关连接

Node操作MongoDB并与express结合实现图书管理系统的更多相关文章

  1. Mongoose 使用Node操作MongoDB

    Mongoose好处 可以为文档创建一个模式结构(Schema) 可以对模型中的对象/文档进行验证 数据可以通过类型转换转换为对象模型 可以使用中间件来应用业务逻辑挂钩 比Node原生的MongoDB ...

  2. 使用node操作mongodb

    let mongodb = require('mongodb'); let MongodbClient = mongodb.MongoClient; MongodbClient.connect('mo ...

  3. node操作mongoDB数据库的最基本例子

    连接数据库 var mongo=require("mongodb"); var host="localhost"; var port=mongo.Connect ...

  4. node操作mongodb

    var mongodb = require('mongodb'); var server = new mongodb.Server('localhost', 27017, {auto_reconnec ...

  5. node操作MongoDB数据库之插入

    在上一篇中我们介绍了MongoDB的安装与配置,接下来的我们来看看在node中怎样操作MongoDB数据库. 在操作数据库之前,首先应该像关系型数据库一样建个数据库把... 启动数据库 利用命令提示符 ...

  6. mongoose - 让node.js高效操作mongodb

    Mongoose库简而言之就是在node环境中操作MongoDB数据库的一种便捷的封装,一种对象模型工具,类似ORM,Mongoose将数据库中的数据转换为JavaScript对象以供你在应用中使用. ...

  7. node.js高效操作mongodb

    node.js高效操作mongodb Mongoose库简而言之就是在node环境中操作MongoDB数据库的一种便捷的封装,一种对象模型工具,类似ORM,Mongoose将数据库中的数据转换为Jav ...

  8. Node使用Mongoose操作MongoDB数据库——增删改查的实现

    当初刚出社会时就规划了下自己的职业生涯:先成为一名优秀的前端工程师,再成为一名全栈工程师(精通前端开发.后台开发和客户端开发),最后成为一名优秀的系统架构师.转眼间已经工作快三年,是时候迈出关键性的一 ...

  9. node.js零基础详细教程(7):node.js操作mongodb,及操作方法的封装

    第七章 建议学习时间4小时  课程共10章 学习方式:详细阅读,并手动实现相关代码 学习目标:此教程将教会大家 安装Node.搭建服务器.express.mysql.mongodb.编写后台业务逻辑. ...

随机推荐

  1. Java Web(四) 一次性验证码的代码实现

    其实实现代码的逻辑非常简单,真的超级超级简单. 1.在登录页面上login.jsp将验证码图片使用标签<img src="xxx">将绘制验证码图片的url给它 2.在 ...

  2. day 73 初学vue (1)

    前情提要: vue 框架的初学习, 主要是,指令,属性,函数,计算属性,监听属性,钩子,生命周期,过滤器,阻止事件和综合案例todo list 学习准备,感谢学习资源: vue 官网:https:// ...

  3. [原创]K8正方系统密码解密工具

    工具: K8_zfsoftDecode编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.163.com发布: 2015/8/1 1 ...

  4. 13-01 java StringBuffer类,StringBuilder类

    StringBuffer类的构造方法 package cn.itcast_01; /* * 线程安全(多线程讲解) * 安全 -- 同步 -- 数据是安全的 * 不安全 -- 不同步 -- 效率高一些 ...

  5. ASM路径问题导致数据库不能正常启动 -- 报:ORA-03113: end-of-file on communication channel

    环境描述: 操作系统版本:Red Hat Enterprise Linux Server release 6.5 (Santiago) 数据库版本:Oracle 11.2.0.4 RAC 场景描述: ...

  6. sql server 2012 打开提示无效的许可证数据。需要重新安装

        重装什么的没有用,需要下载Visual Studio 2010 Isolated Shell (zh-CN) ,重新安装后就好了   下载地址 Visual Studio 2010 Isola ...

  7. Mysql压缩包版的安装方法详解

    Mysql安装的时候可以有msi安装和zip解压缩两种安装方式.zip压缩包解压到目录,要使用它还需对它进行一定的配置.下面对Mysql压缩包版的安装方法进行详细的描述,要是此文有不正确的认识,希望大 ...

  8. 五:理解控件的运行机制(例:基于Control命名空间的简单控件)

    一:先用最简短的话说点理论的1.asp.net中所有的标准控件都可以重写 2.和控件相关的命名空间有 System.Web.UI.Control是所有控件的基类只提供简单的呈现逻辑,不支持样式表 Sy ...

  9. 配置codis-dashboard

    codis-dashboard主要用来codis配置使用,也就是说所有的相关的配置项必须通过此进程完成,本演习在60服务上配置测试. 利用codis本身提供的命令自动生成配置文件:1.生成dashbo ...

  10. RETE算法介绍

    RETE算法介绍一. rete概述Rete算法是一种前向规则快速匹配算法,其匹配速度与规则数目无关.Rete是拉丁文,对应英文是net,也就是网络.Rete算法通过形成一个rete网络进行模式匹配,利 ...