动态定义mongoose模型方法

时间:2015-09-11 09:10:45

标签: javascript node.js mongodb dynamic mongoose

我是在一个函数能够根据情况搜索不同字段的情况下。

它返回相同的数据集,只搜索不同的字段:userId或tagId。因此,在我的代码中我有这样的东西:

var findByMethod;

if (searchBy === 'userId') {
    findByMethod = UserArticleModel.findByUser;
}

else {
    findByMethod = UserArticleModel.findByTag;
}

findByMethod(idToSearch, function (err, articles) {…});

findByUserfindByTagUserArticleModel.js

中定义的静态方法

UserArticleModel.js

var mongoose = require('mongoose');

var userArticleSchema = new mongoose.Schema({
        …
    }
});

userArticleSchema.statics.findByUser = function (userId, callback) {
    this.find({userId: userId}, function () {…});
};

userArticleSchema.statics.findByTag = function (tagId, callback) {…};

module.exports = mongoose.model('UserArticle', userArticleSchema);

当我这样做时,回到我的控制器中:

UserArticleModel.findByTag(idToSearch, function (err, articles) {…});

一切顺利,事情顺利。但是当我通过变量动态调用方法时:

findByMethod(idToSearch, function (err, articles) {…});

当节点返回错误时出现问题:

DOMAINE ERROR CAUGHT: TypeError: Object #<Object> has no method 'find'

我怀疑this不能被约束到正确的范围,但我不能理解为什么findByMethod === UserArticleModel.findByUser // true

1 个答案:

答案 0 :(得分:1)

我认为你需要做的更多参与。虽然它很容易陷入“#34;太字面上”#34;以下记录的API示例和基本上&#34;这就是我需要对此进行硬编码的方式,因为文档说这就是你如何做到的#34;

JavaScript对象是&#34;对象&#34;,因此只是分配&#34;命名&#34;实际上只是对象属性的静态方法只是一个基本过程循环&#34;已定义的&#34;架构路径&#34;从已定义的&#34;对象&#34;并设置&#34; findByFieldName&#34;的属性;你想要的方法。

它只是&#34;分配命名属性&#34;没有什么比这更模糊或更复杂,甚至更像是&#34;简洁&#34;不止于此。

如果那个&#34;听起来像一个满口的&#34; 那么迭代对象属性的实际过程和&#34;设置其他属性&#34;与整体对象结构相关的内容并不像你想象的那么难。

作为一个简短的例子:

var async = require('async'),
    pascal = require('to-pascal-case'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var testSchema = new Schema({
  fieldA: String,
  fieldB: Number
});

function setStatics(schema) {
  Object.keys(schema.paths).filter(function(key) {
    return key != '_id';
  }).forEach(function(key) {
    schema.statics['findBy' + pascal(key)] = function(arg,callback) {
      var query = {};
      query[key] = arg;
      this.findOne(query,callback);
    };
  });
};

// Set up findByFieldName other than _id
setStatics(testSchema);

var Test = mongoose.model( 'Test', testSchema, "test" );

mongoose.connect('mongodb://localhost/test');

async.series(
  [
    function(callback) {
      Test.remove({},callback);
    },
    function(callback) {
      Test.create([
        { "fieldA": "a", "fieldB": 1 },
        { "fieldA": "b", "fieldB": 2 }
      ],callback);
    },
    function(callback) {
      Test.findByFieldA("a",function(err,doc) {
        console.log(doc);
        callback(err);
      });
    },
    function(callback) {
      Test.findByFieldB(2,function(err,doc) {
        console.log(doc);
        callback(err);
      });
    }
  ],
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

这证明他们通过&#34;测试他们&#34;输出:

{ _id: 55f2ae1b7d8315f40b1a2b77, fieldA: 'a', fieldB: 1, __v: 0 }
{ _id: 55f2ae1b7d8315f40b1a2b78, fieldA: 'b', fieldB: 2, __v: 0 }

这就是它的全部内容。

当然对于&#34; Arrays&#34;等领域你希望得到更多的参与,但这是一个基本的前提,你可以自己尝试一下(或者一般社区自我)。

我还可以注意到,已经存在一些问题,例如Bluebird通过它自己的.promisifyAll()调用,它与对象进行交互以设置新的&#34;命名方法& #34;以类似的方式对象。或者至少它原则上应该是相似的,因为我实际上没有看过那段代码。