带你梳理Mongoose模块下MongoDB中的进阶操作
为确保下面的内容是有意义的,请保证在阅读前保证对mongoose模式下的MongoDB数据库的增删改查(CURD)有清晰的理解和认识,如果对mongoose模块下数据库增删改查没有熟练掌握,请务必捋清楚基础概念,多次尝试
准备工作
后文中的model基于以下的schema创建
var UserSchema = mongoose.Schema({
name:String,
sex:String,
age:Number,
job:String,
email:String,
phoneNumber:String,
});
var userModel = mongoose.model('User',UserSchema);
Mongoose 预定义模式修饰符
在创建schema的时候,一般是这样写的
……
name:String,
age:Number,
……
想要字段后面跟上数据类型(SchemaTypes)
(我们顺便来复习一下)
以下是 mongoose 的所有合法 SchemaTypes:
String
Number
Date
Buffer
Boolean
Mixed
ObjectId
Array
Decimal128
其实对于我们后期实例化(model)以后增加数据的时候,可以对增加的数据进行一些格式上的规范
name:{
type:String,
trim:true,
lowercase: true
}
age:{
type:Number,
default:1
}
你可以直接声明 schema type 为某一种 type,或者赋值一个含有 type
属性的对象,而我们对于格式的规范就写在这个对象里
下面我们来介绍一下几个常见的预定义模式修饰符
trim修饰符
我们在某些网站创建账号的时候,经常会遇到重名的情况,网站往往是不允许重名的
比如有人叫:小张同学。而有些人也想在这个网站取这名字,就会尝试在这个名字后面加几个空格,空格也算字符
比如:(空格)小张同学(空格)(空格)(空格)ps:以为自己很聪明是不是,太天真了
如果我们在schma中预设 name 这个字段的模式修饰符 trim 为true的话,在写入数据库的时候,会自动过滤掉这条数据前后的空格
name:{
type:String,
trim:true,
}
输入的数据:(空格)小张同学(空格)(空格)(空格)
实际写入数据库的数据:小张同学
lowercase、uppercase修饰符
同样的,预设 name 这个字段的模式修饰符 lowercase 或者 uppercase 为true的话,会将数据转化为小写或者大写
name:{
type:String,
lowercase:true,
}
输入的数据:ABbaYy
实际写入数据库的数据:abbayy
name:{
type:String,
uppercase:true,
}
输入的数据:ABbaYy
实际写入数据库的数据:ABBAYY
required修饰符
required : 表示这个数据必须传入
name:{
type:String,
required:true,
}
//不传入这个字段的数据,无法保存这条数据到数据库中,不信你试试
default修饰符
我们不妨来看一下default的中文含义:默认; 系统设定值; 预置值
你不难理解,default实际上就是在添加默认值,任何值或函数和函数都可以通过default设置,如果是函数,函数返回值为默认值
我们知道,在MongoDB中,如果按照原来的写法,没有Mongoose 预定义模式修饰符的话,我们针对这个字段不写入数据,实际在数据库对于这个字段是不会有数据的,但是我们如果在字段里预设default一个值,如果我们不写入这个字段的话,数据库会自动把我们的默认值写入这个字段
name:{
type:String,
}
age:{
type:Number,
default:100
}
输入的数据: name:小张同学
实际写入数据库的数据: name:小张同学,age:100
比较常见的场景是这样的,我们发动态或者朋友圈的时候会发现有一个发布时间,这个是怎么实现的呢?
我们在schema的创建中预留一个CreateAtDate字段用来储存保存时间,每当我写入数据库的时候
就会默认把当前时间写入数据库
CreateAtDate: { //用户创建时间
type:Date,
default: Date.now() //javascript中的内置函数,不要和我说你不会用
}
用于验证String类型数据的修饰符
match修饰符
用法 match: 正则表达式
创建验证器,检查这个值是否匹配给定正则表达式(一般数据的验证给前端的同学做了,不过二重验证也是可以的嘛)
age:{
type:Number,
default:100,
match:/\d+/
}
/\d+/表示必须是数字
enum修饰符
用法 enum:[ 你给定的数组]
创建验证器检查这个值是否包含于给定数组(你写入的值必须是我给定的数组里的,不然无法写入数据库)
language: {
type: String,
enum: ['Chinese', 'English']
} //写入的值必须是数组中两个元素之一
maxlength,minlength修饰符
用法 maxlength:数字
minlength:数字
限制字符串的长度,比如说密码是12位到16位
password: {
type: String,
maxlength:16
minlength:12
}
小结:验证string类型的字段的数据,有match,enum,maxlength, minlength四种常见方法,这四个方法是可以叠加使用的
Number数据类型的验证修饰符
min: 数值 创建验证器检查属性是否大于或等于该值
max: 数值 创建验证器检查属性是否小于或等于该值
age:{
type:Number,
max:200, //没见过这么大岁数的
min:1 //1岁就会注册帐号了,小朋友有点东西
}
有关索引的修饰符
index: 布尔值 是否对这个属性创建索引
unique: 布尔值 是否对这个属性创建唯一索引
sparse: 布尔值 是否对这个属性创建稀疏索引
name:{
type:String,
index:true,
}
name:{
type:String,
unique:true,
}
Get与 Set修饰符(自定义)
除了 mongoose 内置的修饰符以外,我们还可以通过 set(建议使用) 修饰符在增加数据的时候对数据进行格式化。也可以通过 get(不建议使用)在实例获取数据的时候对数据进行格式化
用法
set(params){
//增加数据的时候对name这个字段进行处理
//params用来获取你输入的值,对params处理以后,返回的数据就是在数据库中保存的数据
}
我们举个栗子
这里我们插播一个广告!呸,插播一个知识点
Search()方法返回第一次出现的位置,不存在返回-1
var str='abcdef';
str.search('u'); //-1(表示不存在)
str.search('b'); //1
name:{
type:String,
set(params){
if(!params){
params = ""; //如果是params没有传入数据,我们进行判断,返回一个空字符串保存到数据库
}else{
if(params.search("云顶书院的")!== -1){ // 判断有没有包含”云顶书院“这个字符串
params = "云顶书院" + params; //没有给它加上
}
return params;
}
}
//输入的数据:小张同学
//实际写入数据库的数据:云顶书院的小张同学
我们来看一下再来看一下get修饰符
name:{
type:String,
get(params){ params用来获取数据库中的值,对params处理以后,返回数据
return "JS方向的" + params
}
}
//这个实例的数据:小张同学
//实际输出的数据:JS方向的小张同学
实际这个get修饰符极其难用
我们使用mongoose的查询函数,查询出来的结果其实还是数据库中本身的样子,没有对name字段进行修饰
比如数据库中有这么条数据 {name:小张同学,age:100}
使用find函数查询后得到的结果会是 {name:小张同学,age:100}
这是怎么肥事,你不是输出结果的时候会修饰这个字段的数据吗?
其实是我们的打开方式不对
var user = new userModel({ //实例化一条数据,这一个实例数据甚至都没有保存到数据库
name:小张同学,
age:100
});
我们这个时候打印出来name字段
console.log(user.name); //输出的结果是:JS方向的小张同学
功能极其难用,谁设计的?建议拖出来枪毙五分钟
复杂条件查询(Query Selectors)
在使用针对于Model的查找方法时,可以对查询的字段有一些限制,我们来看一下常见的几个
比较查询运算符(Comparison)
比较查询运算符 | 含义 |
---|---|
$eq | 等于 :匹配等于指定值的值 |
$gt | 大于: 匹配大于指定值的值 |
$gte | 大于等于: 匹配大于或等于指定值的值 |
$in | 匹配数组中指定的任何值 |
$lt | 小于 :匹配小于指定值的值 |
$lte | 小于等于 :匹配小于或等于指定值的值 |
$ne | 匹配不等于指定值的所有值 |
$nin | 匹配数组中指定的任何值 |
我们来看几个实例(很简单哒)
userModel.find({age: {$lt: 100} }, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
//查询“age”中小于100的数据
userModel.find({name: {$in: ["Lebron", "kuzma", "Davis"] } }, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
//查询“name”为"Lebron", "kuzma", "Davis"的三个人
逻辑查询运算符(Logical)
就像我们在编程语言中学习的一样,或且非三种
逻辑查询运算符 | 含义 |
---|---|
$and | 且 将返回与两个查询条件匹配的所有文档 |
$not | 奇怪的非 反转查询表达式的效果,并返回与查询表达式不匹配的文档 |
$nor | 非 将返回无法匹配这两个子句的所有文档 |
$or | 或 将返回与任一查询条件匹配的所有文档 |
写法一:userModel.find({ $and: [
{age: {$gte: 20}},
{age: {$lt: 40}}
]}, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
//查询age字段值大于等于20到小于40的数据
userModel.find({ $nor: [
{age: 30},
{age: 50}
]}, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
查询age字段值不等于20和不等于40的数据
元素查询运算符(Element)
就是在查询数据是否存在这么一个字段,把存在这个字段的数据全查出来
元素查询运算符 | 含义 |
---|---|
$exists | 查询的字段值是否存在 : 匹配具有指定字段的文档 |
userModel.find({name:{$exists: true} }, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
//查询存在“name”字段的数据
常用的运算符
评估查询运算符
评估查询运算符 | 含义 |
---|---|
$mod | 与数据进行取模运算筛选 |
$regex | 使用正则表达式查询数据 |
$where | 支持js表达式查询 |
$mod:
userModel.find({ age: {$mod: [12, 0]}}, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
查找age字段中,数值与4取余后,值为0的数据
$regex:
userModel.find({ name: { $regex: "L+","$options":"i"}}, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
搜索以“L”开头的"name",“options”中的“i”代表不区分大小写(你要是学过正则就好理解了)
$where:
userModel.find({ $where: 'this.comments.length === 10 || this.name.length === 5' },
function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
数组查询运算符
针对数组字段的一些查询操作
数组查询运算符 | 含义 |
---|---|
$all | (查询数组的本身及超集)匹配包含查询中指定的所有元素的数组 |
$elemMatch | (查询数组的交集)如果数组字段中的元素与所有指定的$elemMatch条件匹配 |
$size | (查询指定大小的数组)如果数组字段具有指定大小,请选择文档 |
$all:
tags: ['nodejs', 'mongoose']
userModel.find({ array: {$all:['Lebron', 'james']} } ,
function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
查询“array”的字段值同时包含有['Lebron', 'james']的数据。只要值中包含此数组即返回数据,若是只包含数组中的一个则不返回此数据。
$elemMatch:
userModel.find({ $elemMatch: { array: 'mongoose', age: 30} }, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
查询“array”为“mongoose”或是“age”为“30”的数据
$size:
userModel.find(array: { $size: 2}, function(err, docs){
if(err){
console.log(err);
}
console.log('查到了:' + docs);
});
查询“array”数组中包含两个元素的数据