npm install mongoose
const mongoose = require('mongoose')
const DB_URL = 'mongodb://localhost/mongoose-test'
mongoose.connect(DB_URL,{useNewUrlParser:true,useUnifiedTopology:true }, (err) => {
if (err) return console.log(err)
console.log('数据库成功连接')
})
// 这种也可以看数据库是否连接成功
mongoose.connection.on('connected', () => console.log('数据库连接成功'))
mongoose.connection.on('error', () => console.log('数据库连接异常'))
mongoose.connection.on('disconnectied', () => console.log('数据库连接断开'))
数据库中的Schema,为数据库对象的集合。schema 是 mongoose 里会用到的一种数据模式,可以理解为表结构的定义;每个 schema 会映射到 mongodb 中的一个 collection,他不具备操作数据库的能力
// 设计 users 表(集合) 定义一个Schema Schema里面的对象和数据库表里面的字段需要一一对应
const UserSchema = new mongoose.Schema({
name: String,
age: Number,
status: 'number'
})
/*
定义数据库模型 操作数据库
model里面的第一个参数 要注意:首字母大写、要和数据库 (集合) 名称对应
这个模型会和模型名称相同的复数的数据库建立连接:如通过下面方法创建,那么这个模型将会操作 users 这个表(集合)
复数 >==== 会给名字多加个s 如:User ===> users Phone ===> phones
*/
const User = mongoose.model('User', UserSchema) // 默认会操作users表
// const User = mongoose.model('User', UserSchmea, 'user') // 默认会操作user表
// 查询
User.find({}, (err, doc) => {
if (err) {
console.log(err)
} else {
console.log(doc)
}
})
const User = mongoose.model('User', UserSchema)
// {查找 status 是1的} ,{只显示name和age, _id不显示},{找两条数据},(回调函数)
User.find({ status: 1 }, {name: 1, age: 1, _id: 0}, {limit: 2}, (err, doc) => {
if (err) return console.log(err)
console.log(doc)
})
User.find({}, (err, doc) => {
if (err) {
console.log(err)
} else {
console.log(doc)
}
})
const User = mongoose.model('User', UserSchema)
/*
先实例化 Model 通过实例化 User Model 创建添加的数据
在实例 .save()
*/
const newUser = new User({ // 实例化模型 传入增加的数据
name: '李四',
age: 18,
status: 1
})
// 第二个参数返回的是 添加成功的数据
newUser.save((err, v) => {
if (err) return console.log(err)
console.log(v)
console.log('添加成功')
})
const User = mongoose.model('User', UserSchema)
// 定义数据
let arr = [
{ name: '小猪', age: 13, status: 0 },
{ name: '小明', age: 32, status: 1 },
{ name: '小红', age: 20, status: 1 },
{ name: '小赖', age: 22, status: 1 },
{ name: '小狗', age: 50, status: 1 },
{ name: '小力', age: 10, status: 0 }
]
// 使用 insertMany 插入多条数据
// doc 就是你添加成功之后给你返回的数据
User.insertMany(arr, (err, doc) => {
if (err) return console.log(err)
console.log('插入成功')
console.log(doc)
})
// 方法2
let newArr = new Array()
arr.forEach((value, index) => {
const info = new User(value)
newArr.push(info)
})
User.insertMany(newArr, (err, doc) => {
if (err) return console.log('数据添加失败')
console.log(doc)
console.log('数据添加成功')
})
const User = mongoose.model('User', UserSchema)
// 把name的值是小四的字段里,age的值改成14
User.updateOne({
'name': '小四'
}, {
'age': 14
}, (err, res) => {
if (err) return console.log('更新失败')
console.log(res)
console.log('更新成功')
})
const User = mongoose.model('User', UserSchema)
// 删除一个status是0的
User.deleteOne({ status: 0 }, (err, doc) => {
if (err) return console.log(err)
console.log(doc)
})
// 删除所有 status是0的
User.deleteMany({ status: 0 }, (err, doc) => {
if (err) return console.log(err)
console.log(doc)
})
Getters:
const UserSchema = new mongoose.Schema({
name: {
type: String,
get(params) {
return '测试' + params
}
},
age: Number,
status: 'number'
})
const User = mongoose.model('User', UserSchema)
const newUser = new User({
name: '小龙',
age: 18,
status: 1,
url: 'https://www.baodu.com'
})
console.log(newUser.name) // 测试小龙
Setters:
const UserSchema = new mongoose.Schema({
name: {
type: String
},
age: Number,
status: 'number',
url: {
type: String,
set(parmas) {
if (!parmas) return ''
const isHttp = parmas.indexOf('http://')
const isHttps = parmas.indexOf('https://')
if (isHttp !== 0 && isHttps !== 0) return 'http://' + parmas
return parmas
}
}
})
const User = mongoose.model('User', UserSchema)
const newUser = new User({
name: '小龙',
age: 18,
status: 1,
url: 'www.baodu.com'
})
console.log(newUser)
/*
{
name: '小龙',
age: 18,
status: 1,
url: 'http://www.baodu.com',
_id: new ObjectId("61fb5217081f1e60d8711b0e")
}
*/
索引是对数据库表中一列或多列的值进行排序的一种结构,可以让我们查询数据库变得更快。MongoDB 的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的查询优化技巧。
mongoose 中除了以前创建索引的方式,我们也可以在定义Schema的时候指定创建索引
const DeviceSchema = new mongoose.Schema({
sn: {
type: String,
//唯一索引
unique: true
},
name: {
type: String,
// 普通索引
index: true
}
})
静态方法
const UserSchema = new mongoose.Schema({
name: String,
age: Number,
status: 'number'
})
// 封装静态查询方法
UserSchema.statics.findByAge = function(age, callback) {
this.find({age}, (err, docs) => {
callback(err, docs)
})
}
const User = mongoose.model('User', UserSchema)
User.findByAge('30', (err, res) => {
if (err) return console.log(err)
console.log(res)
})
实例方法 (基本不用)
const UserSchema = new mongoose.Schema({
name: String,
age: Number,
status: 'number'
})
// 实例方法
UserSchema.methods.print = function() {
console.log(this)
}
const User = mongoose.model('User', UserSchema)
const user = new User({
name: '小刘',
age: 18,
status: 1
})
user.print()
/*
{
name: '小刘',
age: 18,
status: 1,
_id: new ObjectId("61fb6b16f14ac45e7d3d9b25")
}
*/
mongoose数据校验是指用户通过mongoose给mongodb数据库增加数据的时候,对数据的合法性进行的验证。
在mongoose里面定义Schema的时候,通过设置字段类型,修饰符、默认参数 、数据校验等都是为了数据库数据的一致性。
属性方法 | 说明 |
---|---|
require | 表示这个数据必须传入 |
max | 用于Number类型数据,最大值 |
min | 用于Number类型数据,最小值 |
enum | 枚举类型,要求数据必须满足枚举值 enum: [‘0’, ‘1’, ‘2’] |
match | 增加的数据必须符合 match (正则) 的规则 |
maxlength | 最大值 |
minlength | 最小值 |
validate(v) | 自定义验证 |
trim | 去除两边的空格 |
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true, // 必须传入
trim: true, // 修饰符 去除两边空格
maxlength: 8, // 最大8位
minlength: 2, // 最小2位
},
age: {
type: Number,
max: 100, // 最大值是100
min: 8 // 最小值是8
},
status: {
type: Number,
enum: [0, 1] // 只能传入0和1
},
url: {
type: String,
match: /^http:\/\/(.*)/i
}
})
const User = mongoose.model('User', UserSchema)
const user = new User({
name: 'zss',
age: 12,
status: 0,
url: 'http://'
})
user.save()
/*
name值为空
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: name: Path `name` is required.\
*/
/*
name长度小于2
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: name: Path `name` (`z`) is shorter than the minimum allowed length (2).
*/
/*
name长度大于8
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: name: Path `name` (`zsdsadsadas`) is longer than the maximum allowed length (8).
*/
/*
status只能传入0和1
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: status: `50` is not a valid enum value for path `status`.
*/
/*
age最大值是100,最小值是8
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: age: Path `age` (102) is more than maximum allowed value (100).
*/
/*
url必须以http://开头
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: url: Path `url` is invalid (http:/).
*/
自定义校验
const UserSchema = new mongoose.Schema({
num: {
type: Number,
validate(value) {
return value % 2 === 0
}
}
})
const User = mongoose.model('User', UserSchema)
const user = new User({
num: 7
})
user.save()
/*
num 必须是偶数
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: num: Validator failed for path `num` with value `7`
*/
$ne:表示not equals 就是不等于的意思
查询某字段不为空的数据
db.user.find({fieldName: {$ne:null}})查询字段等于空的数据
db.user.find({fieldName: {$eq:null}})
$exists:表示是否存在。值为false表示不存在,值为true表示存在
查询某字段不为空的数据
db.user.find({fieldName:{$exists:true}})查询某字段不存在的数据
db.user.find({fieldName:{$exists:false}})
mongoose中获取ObjectID
引入
mongoose
使用mongoose.Types.ObjectId('xczxcxzczxcz3234')
const User = mongoose.model('User', UserSchema)
User.aggregate([
{
$lookup: {
from: 'phones',
localField: 'phone_id',
foreignField: '_id',
as: 'user_phone'
}
},
{
$match: {
'phone_id': { $exists: true }
}
}
], (err, docs) => {
console.log(docs)
})
/*
from: user 这是要关联 user 表
localField 这是要跟 article 表里的 classify_id 字段进行关联
foreignField 这是要跟 user 表里的 _id字段进行关联
as 这是别名,就是给这个新的数据起个名
*/
const { Article } = require('./db')
// 要关联多个表就继续往下写 { $lookup: {...} }
Article.aggregate([
{
$lookup: {
from: 'articlecate',
localField: 'classify_id',
foreignField: '_id',
as: 'cate'
}
},
{
$lookup: {
from: 'user',
localField: 'author_id',
foreignField: '_id',
as: 'user'
}
}
], (err, docs) => {
console.log(JSON.stringify(docs))
})
多表关联查询结果
[
{
// 这个是article表
"_id": "61fb9de67d8a21e93c2eaad2",
"title": "第一个科技文章",
"classify_id": "61fb9619215153325d17a193",
"author_id": "61fb9bdee12c49d0f430d216",
"author_name": "张三",
"description": "这是张三发布的第一个科技文章,属于科技分类",
"content": "这是科技 文章的内容,此处省略一万字",
"__v": 0,
// article表 关联了 articlecate表 并且起名叫cate
"cate": [{
"_id": "61fb9619215153325d17a193",
"title": "科技新闻",
"description": "科技新闻的描述。。。",
"__v": 0
}],
// article表 关联了 user表 并且起名叫user
"user": [{
"_id": "61fb9bdee12c49d0f430d216",
"username": "zhangsan",
"password": "123456",
"name": "张三",
"age": 18,
"sex": "男",
"tel": 14895466411,
"__v": 0
}]
},
{
"_id": "61fb9de67d8a21e93c2eaad3",
"title": "第二个科技文章",
"classify_id": "61fb9619215153325d17a193",
"author_id": "61fb9bdee12c49d0f430d216",
"author_name": "张三",
"description": "这是张三发布的第二个科技文章,属于科技分类",
"content": "这是科技文章的内容,此处省略一万字",
"__v": 0,
"cate": [{
"_id": "61fb9619215153325d17a193",
"title": "科技新闻",
"description": "科技新闻的描述。。。",
"__v": 0
}],
"user": [{
"_id": "61fb9bdee12c49d0f430d216",
"username": "zhangsan",
"password": "123456",
"name": "张三",
"age": 18,
"sex": "男",
"tel": 14895466411,
"__v": 0
}]
},
{
"_id": "61fb9de67d8a21e93c2eaad4",
"title": "第一个金融文章",
"classify_id": "61fb96563188bc6d398ed013",
"author_id": "61fb9bdee12c49d0f430d216",
"author_name": "张三",
"description": "这是张三发布的第一个金融文章,属于金融分类",
"content": "这是金融文章的内容,此处省略一万字",
"__v": 0,
"cate": [{
"_id": "61fb96563188bc6d398ed013",
"title": "金融新闻",
"description": "金融新闻的描述。。。",
"__v": 0
}],
"user": [{
"_id": "61fb9bdee12c49d0f430d216",
"username": "zhangsan",
"password": "123456",
"name": "张三",
"age": 18,
"sex": "男",
"tel": 14895466411,
"__v": 0
}]
}
]
//Article表
// 分类ID
classify_id: {
type: mongoose.Types.ObjectId,
ref: 'ArticleCate' // 关联的Model
},
// 作者ID
author_id: {
type: mongoose.Types.ObjectId,
ref: 'User'
},
// app.js
const { Article } = require('./db')
// populate('classify_id') 需要关联的字段
Article.find({}).populate('classify_id').populate('author_id').exec((err, docs) => {
console.log(docs)
})
这是返回的数据,这里不能起别名,直接就覆盖字段了
{
_id: new ObjectId("61fb9e5735882d989cf8833a"),
title: '第二个美食文章(小红)',
classify_id: {
_id: new ObjectId("61fb9645c342558ade4e1f3c"),
title: '美食新闻',
description: '美食新闻的描述。。。',
__v: 0
},
author_id: {
_id: new ObjectId("61fb9bdee12c49d0f430d219"),
username: 'xiaohong',
password: '123456',
name: '小红',
age: 18,
sex: '女',
tel: 15478932000,
__v: 0
},
author_name: '小红',
description: '这是小红发布的第二个美食文章,属于美食分类',
content: '这是美食文章的内容,此处省略一万字',
__v: 0
}
性能还是推荐使用 aggregate