动态定义猫鼬模型方法

Defining mongoose Model Methods Dynamically

本文关键字:模型 方法 定义 动态      更新时间:2023-09-26

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

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

var findByMethod;
if (searchBy === 'userId') {
    findByMethod = UserArticleModel.findByUser;
}
else {
    findByMethod = UserArticleModel.findByTag;
}
findByMethod(idToSearch, function (err, articles) {…});

findByUserfindByTag是在UserArticleModel.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

我认为你把它弄得更复杂了。虽然这是一个很容易落入的陷阱,"过于逐字逐句"地遵循文档中的API示例,并基本上认为"这就是我需要硬编码的方式,因为文档说这是你应该做的"

JavaScript对象是"对象",因此只是分配"命名"静态方法,这实际上只是对象属性,只是一个基本的过程,从已经定义的"对象"中"循环"定义的"模式路径",并为"findByFieldName"方法设置属性。

它只是"分配命名属性",没有比这更晦涩、更复杂、甚至更"简洁"的了。

如果"听起来有点拗口",那么在整个对象结构中迭代对象属性和"设置其他属性"的实际过程并不像您想象的那么难。

举个简单的例子:

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();
  }
);

通过输出"测试它们"来证明它们是有效的:

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

这就是它的全部。

当然,对于像"Arrays"这样的字段,您希望更多地参与其中,但这是作为一个列表的基本前提,您可以自己尝试(或一般社区的自我)。

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