Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mongoose返回数据修改中遇到的坑 #13

Open
MrErHu opened this issue Jun 14, 2017 · 1 comment
Open

Mongoose返回数据修改中遇到的坑 #13

MrErHu opened this issue Jun 14, 2017 · 1 comment
Labels

Comments

@MrErHu
Copy link
Owner

MrErHu commented Jun 14, 2017

  之前接手了一个微信公众号的项目,项目的技术栈是: 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判断登录用户,去对每条评论判断是否该登录用户已经点赞,那么我想要在返回的数据中临时增加一个字段isPraisetrue代表是当前登录用户已经点赞,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比较好。

@MrErHu MrErHu added the NodeJs label Jun 14, 2017
@Jankos-Lee
Copy link

这个lean妙啊,我就是回去schema新增...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants