Que's Blog

WebFrontEnd Development

0%

mongoDB笔记(三)

mongoose续

前一篇笔记只是非常简单的说了下mongoose下怎样对collection进行增删查改,所以这里做做笔记说说别的开发过程中可能遇到的琐碎。

关于查询

安全

闲话不说,直接看图:

这个图在第二篇笔记里面见过。它有什么问题吗?没有,但是也许可以有:比如说,那个”_id”就是不需要的数据,如果所有的数据都直接这样返回,那么必然会存在一些商业机密信息暴露——尤其是你的user collections里面包含用户手机号码和地址时候。
我们来优化一下流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
router.get('/user', function(req, res, next) {
User.find().exec(function(err,users){
res.json({
code:200,
msg:"success",
data:{
users:users.map(function(o){
return {
name:o.name,
age:o.age
}
})
}
});
})
});

当然,map可能不是非常优雅,但是,还有select可以做到限制字段输出,这里说map,是因为最初自己使用的这个办法处理问题。select具体后文有写到。

静态方法

很多时候状态作为数字存入数据库,做后端数据库的同学应该很熟悉,经常用前端模板渲染json到页面的前端ers也会非常熟悉。在mongoose里面也定义了这样一类方法。我们做个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var mongoose = require('mongoose');
var db = mongoose.connection;
var conn = mongoose.connect('mongodb://que01:<youhost>:<youport>/learn');

var schema = new mongoose.Schema({ name: 'string', age: 'number' });
schema.methods.isAdults = function(){//一个很简单的辅助函数,返回是否成年人
return this.age>18?"成年人":"未成年人";
}
var User = mongoose.model('user', schema);


...
return {
name:o.name,
age:0.age,
isAdults:o.isAdults()
}
...

除了这种最简单的静态方法,在静态方法中还可以调用model进行查询:

1
2
3
schema.methods.sex = function(user){//假装数据里面已经有age属性了吧...这是一个获取相同性别人集合的一个方法
return this.model.find({sex:this.sex},user);
}

关于限制性查询

『SELECT * FROM table ORDER BY id』,想起这类查询,我就想起曾经学过的mysql和php,很熟悉的感觉,哈哈哈。
在mongoose里面当然不是这样查询了,作为一个框架,它必然也会提供类似这种Order By的排序方法。
我在网上找了个相对全的代码片段,就懒得自己写了:

1
2
3
4
5
6
7
8
9
Person
.find({ occupation: /host/ })
.where('name.last').equals('Ghost')
.where('age').gt(17).lt(66)
.where('likes').in(['vaporizing', 'talking'])
.limit(10)
.sort('-occupation')
.select('name occupation')
.exec(callback);

这里总结一下在查询过程中会遇到的情形:

  • 属性值是确定的字符串,而不是一个区间时候,直接在find环节传递参数进去
  • 第二个环节对有区间的数字这种进行限制,如代码中的gt和lt,代表意思是大于17小余66
  • 限制查询条目用limit传入数字进行限制
  • 最后,限制字段使用select传入使用空格分隔的字符串作为需要的字段

当然,如果是非常简单的查询,只是需要限制字段的话,可以这样:

1
2
3
4
5
6
7
8
9
10
11
router.get('/user',"name age",function(req, res, next) {
User.find().exec(function(err,users){
res.json({
code:200,
msg:"success",
data:{
users:users
}
});
})
});

恩,这就是最开始的代码片段除了select的另外的一种解决办法。

查询的静态方法

最后说下查询的方法,查询可以使用的方法有三个

  1. find(query)
  2. findOne(query)
  3. findById(ObjectID)

find

find这个应该无需多说了,在前面已经有了太多例子了。

findOne

接受一个查询条件,返回单个数据,这个方法,在一些限制性的collection中非常有用,例如很多保存操作会在进行保存之前判断是否用重复,这个最常见的是管理员帐号collection限制用户名不能相同和用户注册collection限制手机和邮件不能相同。

findById(ObjectID)

应该来说这个性能最高。如果能获取ObjectID,使用它替代findOne,无需进行任何query查询直接获取结果。

关于增加

在mysql这类sql数据库里面,数据是强制限制的,如果不符合会被拒绝写入,但是mongoDB作为NoSql数据库是不限制类型的,这意味着当将mongoDB作为关系型数据库时候需要自己承担这个验证的过程,mongoose里面已经为我们做了这个接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var conn = mongoose.connect('mongodb://que01:<youhost>:<youport>/learn');
var schema = new mongoose.Schema({
name:{
type:'String',
required:true //姓名非空
},
age:{
type:'Nunmer',
min:18, //年龄最小18
max:120 //年龄最大120
},
city:{
type:'String',
enum:['北京','上海'] //只能是北京、上海
}
});
var User = mongoose.model('user', schema);

关于更新

用关数据更新的Model辅助方法

  1. update()
  2. findOneAndUpdate() 这个之前有过演示
  3. findByIdAndUpdate()

这三个方法都接受相同的四个参数:

  1. conditions 查询条件
  2. update 一个对象,里面放想要设置的键值对
  3. options 一个对象,里面设置一些特殊的操作
  4. callback 回调函数,执行更新之后的回调

这里简单说下options这个选项,在三个方法中,它有所不同

options在update()中

  • safa 布尔值,是否抛出错误给callback,默认值是schema中设置的。如果没有设置,缺省值是true
  • upsert 布尔值,当没有匹配document是否新建一个,缺省值为false
  • multi 布尔值,是否多个文档可以一起更新,默认为false
  • strict 是否只有schema已定义的数据才能被保存,默认值是true

findOneAndUpdate()&findByIdAndUpdate中

  • new 布尔值,是否返回最初被修改过的document,默认为true
  • upsert 布尔值,如果查询文档不存在则新建一个,默认为false
  • sort 接受一个object,对查到的数据排序
  • select string,空格分隔的字段组成的字符串

更新步骤

更新数据是个复合动作,包括三个动作:查、改、存。所以说,即使不实用update方法,使用find,手动实现修改后,save()之,也是一个完整的更新过程。
但是这里我们来使用update更新数据会更快,更方便(其实更方便我觉得是最重要的):

1
2
3
4
5
6
7
User.update(
{_id:user.id},
{$set:{lastLogin:new Date()}},
function(){
//code here...
}
)

是不是很简单?update将读、改、保存合为一体了,这就是它的『快』,但是除了这个快之外,还有一个更方便地方:
它只是更新了lastLogin值,而别的值秋毫无犯,这是和save非常显著的区别,save()时候如果不传入完整数据,那么没有传入的数据就会被schema中默认值替代!

恩,关于更新,就是这么多了,更多例子就不补充了。继续删除。

关于删除

类似更新,它有很类似的方法:

  1. remove()
  2. findOneRemove()
  3. findByIdAndRemove()

remove貌似不用再作介绍了,在之前笔记有过若干例子。
这里说说后面两个方法,他们接受相同的参数:

  • Query Object 查询对象 输入对象进行匹配和删除
  • Options 一个对象,接受两个属性: sort(对匹配文档排序)和 select(设置返回给callback的对象的属性)
  • Callback 一个回调函数,好像无需说更多

总结

就这样吧,虽然还是不是很详细,但是作为一份笔记和总结来说,这已经足够。mongoose的中文资料不多,深入的更少,这里就仅仅就CURD进了相对深入的记录,聊做记忆强化和备忘。

--This is All--tks