【问题标题】:Generate mongoose DTO for MEAN application为 MEAN 应用程序生成猫鼬 DTO
【发布时间】:2015-09-22 11:51:55
【问题描述】:

我是 mongoose 和 node 的新手,我正在使用 MEAN 堆栈(Mongo ExpressJS AngularJS Node)构建一个应用程序。

我过去使用 asp.net WebAPI 构建了很多 API,但我找不到任何关于使用 DTO 或 View Models 的文档,以减少我之间来回传输的 JSON 量服务器和我的前端。

我的申请是关于用户在线填写的调查。然后,每个答案都会被用户用来产生一个分数。

我的模型:

var UserSchema = new Schema({
    email: {type: String, trim: true,default: '', match: [/.+\@.+\..+/,'']},
    status: {type: String},
    token:{type: String, default: crypto.randomBytes(64).toString('hex')},
    score: {
        managementExperience: {type: Number},
        managementSkills: {type: Number},
        relevantKnowledge: {type: Number},
        commitment: {type: Number},
        acceptanceOfChange: {type: Number},
        age: {type: Number},
        totalScore: {type: Number}
    },
    answers: [
        {
            optionId: {type: Schema.Types.ObjectId}
        }
    ]
});

var SurveySchema = new Schema({
    client_id:{type: Schema.Types.ObjectId, ref: 'Client' },
    creationDate:{type: Date,default: Date.now},
    title: {type: String, trim: true},
    surveyVersion: { type: Schema.Types.ObjectId, ref: 'SurveyVersion' },
    users:[UserSchema]
});

调查屏幕本身可以工作,但是在生成结果仪表板时,我想发送一个 DTO 而不是整个 SurveySchema,就像这个模型:

var SurveySchemaLight = new Schema({
    client_id:{type: Schema.Types.ObjectId, ref: 'Client' },
    creationDate:{type: Date,default: Date.now},
    title: {type: String, trim: true},
    users:[{
        email: {type: String, trim: true,default: '', match: [/.+\@.+\..+/,'']},
        status: {type: String}
    }]
});

在 .Net 世界中,我希望这个模型有一个构造函数,该构造函数将 SurveySchema 的实例作为参数,但我找不到让它工作的方法。

我还尝试将两个 Schema 链接到 mongodb 中的同一个集合:

mongoose.model('Survey', SurveySchema);
mongoose.model('SurveyLight', SurveySchemaLight, 'surveys');

但是当我在 SurveyLight 架构上运行以下查询时,我仍然返回了来自 Survey 的所有字段:

SurveyLight.find({'client_id': req.params.clientID}).exec(function(err, surveyList){
        res.json(surveyList);
    });

在我的堆栈中拥有 DTO/视图模型机制的最佳实践是什么?

谢谢

【问题讨论】:

    标签: node.js mongodb express mongoose


    【解决方案1】:

    对于一般的“mongoose”和 MongoDB 查询,您只需在输出中“投影”您需要的字段,而忽略其他您不想要的字段。

    作为一个独立的例子:

    var async = require('async'),
        mongoose = require('mongoose'),
        Schema = mongoose.Schema;
    
    var childSchema = new Schema({
      "longName": String,
      "email": String,
      "status": String
    })
    
    var parentSchema = new Schema({
      "name": String,
      "longDescription": String,
      "children": [childSchema]
    })
    
    mongoose.connect('mongodb://localhost/test');
    
    var Parent = mongoose.model( 'Parent', parentSchema );
    
    async.waterfall(
      [
        // remove any samples
        function(callback) {
          Parent.remove({},function(err,res) {
            callback(err)
          });
        },
    
        // insert some test data
        function(callback) {
          Parent.create(
            {
              "name": "Bill",
              "longDescription": "Something we don't want to see",
              "children": [
                { "longName": "don't want", "email": "a@example.com", "status": "A" },
                { "longName": "don't want", "email": "b@example.com", "status": "B" }
              ]
            },
            function(err,doc) {
              console.log( doc );
              callback(err,doc);
            }
          )
        },
    
        // Fetch just the fields we want
        function(doc,callback) {
          Parent.find({},"name children.email children.status", callback);
        }
      ],
    
      // Ouput results
      function(err,result) {
        if (err) throw err;
        console.log(result);
        process.exit();
      }
    );
    

    以下形式的输出:

    // The original form of the documents
    { __v: 0,
      name: 'Bill',
      longDescription: 'Something we don\'t want to see',
      _id: 5598b6bad439a31807bfe746,
      children:
       [ { longName: 'don\'t want',
           email: 'a@example.com',
           status: 'A',
           _id: 5598b6bad439a31807bfe748 },
         { longName: 'don\'t want',
           email: 'b@example.com',
           status: 'B',
           _id: 5598b6bad439a31807bfe747 } ] }
    
    // The output document with just selected fields
    [ { _id: 5598b6bad439a31807bfe746,
        name: 'Bill',
        children:
         [ { email: 'a@example.com', status: 'A' },
           { email: 'b@example.com', status: 'B' } ] } ]
    

    如果您想“排除”字段而不是显式命名它们,请以 - 为前缀,如

    "-longName -children.logDescription"
    

    但您不能“混合”这两个术语,"-_id" 除外

    【讨论】:

    • 谢谢布雷克斯,我不知道用这种语法列出要输出的字段!
    【解决方案2】:

    在 JavaScript 世界中,您应该尝试从函数式编程的角度来解决这个问题。你有一些数据,你想返回这个数据的一个子集。您不需要单独的模型定义,只需要一个映射/过滤器功能。

    例如

    SurveyLight.find({'client_id': req.params.clientID}).exec(function(err, surveyList){
            var parsedSurveyList = surveyList.map(function(survey){
              survey.users = survey.users.map(function(user){
                return {email: user.email, status: user.status};
              });
              return survey;  
            });
            res.json(parsedSurveyList);
        });
    

    您可以通过使用流行的函数库(例如 lodash)来改善这一点。

    【讨论】:

    • 谢谢 Yuri,我更想知道是否可以使用猫鼬机制来避免这种代码。
    猜你喜欢
    • 2013-07-27
    • 2015-08-16
    • 2014-12-06
    • 2015-09-17
    • 2017-05-29
    • 2019-05-30
    • 2019-09-16
    • 1970-01-01
    • 2018-12-12
    相关资源
    最近更新 更多