mongoose的基本操作

前言

mongoose与mongodb的关系

mongodb实际上是一个跨平台的nosql型数据库软件,而mongoose是一个基于mongodb官方js驱动实现的js库,即专门用于在node.js环境下与mongodb数据库进行连接操作。

为什么使用mongoose

事实上mongodb官方已经实现了基于node.js的驱动库,npm包名就叫mongodb,专门用来与mongodb数据库进行连接操作的,所以为何还要使用第三方实现的mongoose库。这是实际上还是取决于每个人的习惯和理念,由于mongodb在设计上就对于collection(对应于sql数据库中的数据表)的结构限制很少,可以认为其存取数据很灵活,也可以认为其存取数据比较松散,这完全是个人口味问题。

我个人比较习惯对于同一集合(collection)中数据的格式要保持一致性,即每条数据的结构和类型是一致的,不然总觉得不同结构和类型的数据存放于同一集合中就太混乱了(也许是还无法适应mongodb的设计模式)。

mongoose就加入了Schema这一设计,使得集合中的数据保持结构和类型的一致性成为可能,方便数据管理。

mark

基本操作

数据库连接

1
2
3
4
5
6
7
8
9
10
11
12
const mongoose = require('mongoose')
// mongodb连接地址:mongodb://ip:port/database
const url = 'mongodb://0.0.0.0:27017/test'

let db = mongoose.createConnection(url) // 返回数据库的连接对象
db.on('error', (err)=>{ // 监听数据库连接错误事件
throw err
})
db.once('open', function(){ // 监听数据库连接成功事件(once就是监听一次)
console.log('connect success')
db.close() // 关闭数据库连接
})

注:mongodb数据库的默认端口为27017

连接集合与Model

Schema可以看做是Modelcollection之间的中介(相当于proxy),因为实际上不同的Schema可以连接到同一个collection,也就是即便是使用mongoose后仍然会出现同一个集合内存在不同数据结构的数据;但是由于有Schema这层中介的存在,使得同一Schema内的数据结构是一致的,就不需要我们自己手动地去集合内约束和判断数据结构了(即把数据结构从集合中抽离出来,集合本身不再有固定的数据结构)。

Model可以看做某个collecton中具有某个Schema一部分数据,即一个Model需要通过某个Schema来对某个collection进行数据操作。

1
2
3
4
5
6
7
8
const mongoose = require('mongoose')
const Schema = mongoose.Schema

const testSchema = {
name: String,
age: Number,
habits: [String]
} // 首先定义一个Schema结构

连接集合的方式有两种,一种是mongoose约定的形式;另一种是给schema指定一个具体的collection,使用此schemamodel都自动连接到这个collection

方法一

1
2
3
4
5
// 方法一:指定一个具体的collection

let schema = Schema(testSchema, {collection: 'info'}) // 将testSchema绑定到名为info的集合上
// db为数据库连接对象,该model自动连接schema绑定的集合上
let model = db.model('Habit', schema)

方法二

1
2
3
4
5
6
// 方法二:根据Model的名称自动查找

let schema = Schema(testSchema) // schema没有绑定集合

// 此时model连接到其名称的复数形式(小写)的集合上,即habits集合
let model = db.model('Habit', schema)

CRUD

插入数据

一条数据即一条document,而每条document都是某个model的实例;所以插入一条数据到某个集合就要先得到该集合的某个Model,然后new一个该Model的实例,填入数据后可以使用save方法进行插入;

1
2
3
4
5
6
7
8
9
10
let schema = Schema(testSchema, {collection: 'info'})
let Habit = db.model('Habit', schema)
let habit = new Habit({
'name': 'xxf',
'age': 22
}) // 可以只填部分或不填数据,新增一条数据

habit.save(err => {
...
}) // 使用save方法对新增的数据进行插入

查询数据


查询条件应该是数据库操作中用的最多的操作,写法自然也是丰富多样,我觉得有必要单独去专门写一个mongoose条件语句(mongoose实际上使用的条件语句格式是mongodb官方规定的语句)的文章,目前还没有使用那么多的语法(主要是还没有遇到那么多的应用场景……)。


mongoose的查询API有:

  • Model.find()
  • Model.findById()
  • Model.findByIdAndDelete()
  • Model.findByIdAndRemove()
  • Model.findByIdAndUpdate()
  • Model.findOne()
  • Model.findOneAndDelete()
  • Model.findOneAndRemove()
  • Model.findOneAndUpdate()

经常使用的方法主要是find()findOne()这两个,前者可以返回多条满足条件的数据,而后者只返回第一条匹配条件的数据;

1
2
3
4
5
6
let schema = Schema(testSchema, {collection: 'info'})
let Habit = db.model('Habit', schema)

Habit.findOne({'name': 'xxf'}, (err, data) => {
...
})

如上,findOne()方法的第一个参数为查询条件,第二个参数为回调函数(回调函数第一个参数为Error对象,当不为undefined时则代表查询发生错误,第二个参数为匹配条件的数据);

1
2
3
4
5
6
let schema = Schema(testSchema, {collection: 'info'})
let Habit = db.model('Habit', schema)

Habit.findOne({'age': {$gt: 18}}, (err, docs) => {
...
})

find()方法的用法几乎与findOne()的一致,只是回调函数的第二个参数是一个数组,包含所有满足查询条件的数据;

更新数据

更新的本质就是先查询后修改,所以也需要用到查询语句;但是除此外还需要用到修改语句,又是有许多内容可讲;

mongoose的更新数据API有:

  • Model.replaceOne()
  • Model.updateMany()
  • Model.updateOne()

删除数据

删除操作也是先进行查询在删除的,所以也要用到查询语句;

mongoose的删除数据API有:

  • Model.deleteMany()
  • Model.deleteOne()

注意事项

当对某条数据的一部分(字段)的内容进行增删操作时,实际上还是属于更新数据的范畴,注意不要混淆!

后话

实际上还有很多需要整理的,但是目前使用的场景并不多,使用的语法的也比较零散,还是需要时间和项目的使用慢慢积累才行。

参考文档

  1. Mongoose v5.3.9: Getting Started
  2. MongoDB CRUD Operations
  3. Query and Projection Operators —— MongoDB Manual