之前接手了一个微信公众号的项目,项目的技术栈是: NodeJs
+ExpressJs
+mongo
+mongoose
+jade
,第一次使用ODM(Object DatabaseManage)工具mongoose
,发现使用起来还是非常方便的,你可以预先定义一个model
,把mongo这种NoSql当做关系型数据库使用,并且通过populate
能基本实现一些比较简单的连接查询 ,但是在使用的过程中也是踩了不少坑,举例讲一个比较典型的:对于mongoose返回数据的修改的问题。
假设我们需要涉及一个关于评论的model
,我们用下面的代码举例:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CommentSchema = new Schema({
topicId: {type: Schema.ObjectId, ref:'Topic',index: true},
author: { type: Schema.ObjectId, ref: 'User'},
group: {type: Number, default: 0, index: true},
content: String,
status: {type: Number, default: 0},
createdAt: { type: Date, default: Date.now },
favNum: {type:Number, default: 0}
});
var Comment = mongoose.model('Comment', CommentSchema);
module.exports = Comment;
上面的代码非常的简单明了,定义了model
的各种字段、类型、引用,这样我们在代码中就可以通过mongoose对mongo进行查询了,有Java的经验老司机会发现这个工具和Hibernate
非常相似。
假设现在我们有一个业务,我需要提供一个Restful Get接口,返回当前文章的评论信息,并且根据session判断登录用户,去对每条评论判断是否该登录用户已经点赞,那么我想要在返回的数据中临时增加一个字段isPraise
,true
代表是当前登录用户已经点赞,false
代表当前用户未点赞。
我们可能会有下面两种mongoose的代码风格
Comment.findOne({
id: commentId,
},function (err,data) {
if(){
//如果用户点赞
data.isPraise = true;
}else{
//如果用户未点赞
data.isPraise = false;
}
});
或者
Comment.findOne({
id: commentId
}).exec(function (err,data) {
if(){
//如果用户点赞
data.isPraise = true;
}else {
//如果用户未点赞
data.isPraise = false;
}
});
上面的代码看起来没有任何的问题,mongoose返回的是Object,我根据自己的业务新增属性,然后以JSON数据返回给用户。但是事实上新增加的属性不能被打印出来(通过console.log(JSON.stringify(data))
)也不能返回给客户端,但是奇怪的是却可以打印出来console.log(data.isPraise)
,而且Object.prototype.hasOwnProperty()
方法返回的也是true
,说明确实已经增加了这个属性,为什么不会返回给请求方呢?
后面经过排查终于发现了问题的所在,实际上mongoose返回的数据并不是object
,虽然你通过typeof
判断类型是object
,实际上是mongoose自己封装的一个对象,并且这个对象会对数据进行实时查询以保证其符合预定义的model
,因为model
中压根就没有isPraise
属性,所以是无法增加的。
现在看来解决方法可以在model
中预先定义isPraise
字段,但是这个并不是没有业务都需要的,所以这种方法太糙了,果断放弃。幸好mongooes提供给我们函数来解决这个问题:lean()
。代码如下:
Comment.findOne({
id: commentId,
},null,{
lean: true
}function (err,data) {
if(){
//如果用户点赞
data.isPraise = true;
}else{
//如果用户未点赞
data.isPraise = false;
}
});
或者
Comment.findOne({
id: commentId
}).lean().exec(function (err,data) {
if(){
//如果用户点赞
data.isPraise = true;
}else {
//如果用户未点赞
data.isPraise = false;
}
});
通过上述方法就可以解决mongoose对返回数据的控制了,你就可以为所欲为了,当然如果不是这种业务,尽量建议少使用,毕竟最好还是使数据符合预先定义的model
比较好。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。