Open MrErHu opened 7 years ago
之前接手了一个微信公众号的项目,项目的技术栈是: NodeJs+ExpressJs+mongo+mongoose+jade,第一次使用ODM(Object DatabaseManage)工具mongoose,发现使用起来还是非常方便的,你可以预先定义一个model,把mongo这种NoSql当做关系型数据库使用,并且通过populate能基本实现一些比较简单的连接查询 ,但是在使用的过程中也是踩了不少坑,举例讲一个比较典型的:对于mongoose返回数据的修改的问题。 假设我们需要涉及一个关于评论的model,我们用下面的代码举例:
NodeJs
ExpressJs
mongo
mongoose
jade
model
populate
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的代码风格
Hibernate
isPraise
true
false
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()。代码如下:
console.log(JSON.stringify(data))
console.log(data.isPraise)
Object.prototype.hasOwnProperty()
object
typeof
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比较好。
这个lean妙啊,我就是回去schema新增...
之前接手了一个微信公众号的项目,项目的技术栈是:
NodeJs
+ExpressJs
+mongo
+mongoose
+jade
,第一次使用ODM(Object DatabaseManage)工具mongoose
,发现使用起来还是非常方便的,你可以预先定义一个model
,把mongo这种NoSql当做关系型数据库使用,并且通过populate
能基本实现一些比较简单的连接查询 ,但是在使用的过程中也是踩了不少坑,举例讲一个比较典型的:对于mongoose返回数据的修改的问题。 假设我们需要涉及一个关于评论的model
,我们用下面的代码举例:上面的代码非常的简单明了,定义了
model
的各种字段、类型、引用,这样我们在代码中就可以通过mongoose对mongo进行查询了,有Java的经验老司机会发现这个工具和Hibernate
非常相似。 假设现在我们有一个业务,我需要提供一个Restful Get接口,返回当前文章的评论信息,并且根据session判断登录用户,去对每条评论判断是否该登录用户已经点赞,那么我想要在返回的数据中临时增加一个字段isPraise
,true
代表是当前登录用户已经点赞,false
代表当前用户未点赞。 我们可能会有下面两种mongoose的代码风格或者
上面的代码看起来没有任何的问题,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()
。代码如下:或者
通过上述方法就可以解决mongoose对返回数据的控制了,你就可以为所欲为了,当然如果不是这种业务,尽量建议少使用,毕竟最好还是使数据符合预先定义的
model
比较好。