【问题标题】:Schemas in external module not working in Node.js外部模块中的模式在 Node.js 中不起作用
【发布时间】:2014-11-20 23:09:50
【问题描述】:

尝试通过一个模块将一些通用架构定义共享给我的代码库中的所有其他模块时,我感到非常头疼。

我有一个包含这两个模式的 myproj_schemas 模块:

var mongoose = require('mongoose'),
    util = require("util"),
    Schema = mongoose.Schema;

var BaseProfileSchema = function() {
    Schema.apply(this, arguments);

    this.add({
        _user: {type: Schema.Types.ObjectId, ref: 'User', required: true},
        name: {type: String, required: true},
        bio: {type: String, required: true},
        pictureLink: String
    });

};
util.inherits(BaseProfileSchema, Schema);

module.exports = BaseProfileSchema;

var mongoose = require('mongoose'),
    BaseProfileSchema = require('./base_profile_schema.js'),
    Schema = mongoose.Schema;

var entSchemaAdditions = {
    mentors: {type: Schema.Types.ObjectId, ref: 'Mentor'}
};


var entrepreneurSchema = new BaseProfileSchema(entSchemaAdditions);

module.exports = entrepreneurSchema;

导师也在另一个文件中定义。

我对这两者的单元测试都在模式模块中工作。

当我 npm 安装此模块并尝试使用创建时

Entrepreneur = db.model('Entrepreneur', entrepreneurSchema),

我收到以下错误:

TypeError:paths.mentors 处的未定义类型 您是否尝试过嵌套模式?您只能使用 refs 或数组进行嵌套。

如果我在本地模块中使用相同的代码,那么没问题。 如果我直接在 require 中引用架构文件(例如 require('../node_modules/myproj_schemas/models/ent_schema') ,则会收到错误消息。

我很确定它之前没有像这样中断,但我已经取消了所有更改,但它仍然无法正常工作。

我正在画一个完整的空白,任何建议都将不胜感激。

编辑:

我创建了一个新的架构模块。它有一个架构:

var mongoose = require('mongoose');

var userSchema = new mongoose.Schema({
    email: String
});

module.exports = userSchema;

当打包在一个模块中并且 npm install'd 到其他模块时,这也会失败。

在 OS X 上运行

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    我个人使用 init 方法创建了单独的“通用”项目,以将所有模型注册到 mongodb,并在需要访问模型的任何应用的 app.js 文件中调用 init 方法。

    1. 创建一个共享项目 - 按照标​​准流程创建一个新的节点项目。
    2. package.json - 在共享项目中,将您的 package.json 文件设置为包含以下条目:

      "main": "index.js"
      
    3. 添加模型 - 在您的共享项目中创建一个新的models 文件夹,以包含您所有的猫鼬模式和插件。将您的 userSchema 文件添加到模型文件夹并将其命名为 user.js

      var mongoose = require('mongoose');
      
      var userSchema = new mongoose.Schema({
          email: String
      });
      
      module.exports = mongoose.model('User', userSchema);
      
    4. index.js - 然后在项目的根 index.js 文件中创建一个可供您的应用使用的共享对象,公开模型和 init 方法。有很多方法可以编写代码,但我是这样做的:

      function Common() {
          //empty array to hold mongoose Schemas
          this.models = {};
      }
      
      Common.prototype.init = function(mongoose) {
          mongoose.connect('your mongodb connection string goes here');
          require('./models/user');
          //add more model references here
      
          //This is just to make referencing the models easier within your apps, so you don't have to use strings. The model name you use here must match the name you used in the schema file
          this.models = {
              user: mongoose.model('User')
          }
      }
      
      var common = new Common();
      
      module.exports = common;
      
    5. 引用您的common 项目 - 如果您想引用您的共享项目,请在您的应用程序的package.json 文件中添加对共享项目的引用,并将其命名为common。我个人使用 GitHub 来存储项目并引用了存储库路径。由于我的存储库是私有的,因此我必须在路径中使用一个密钥,这在 GitHub 支持网站上有介绍。
    6. 在您的应用程序中初始化模型 - 在您的应用程序的启动脚本中(在此示例中假设它是 app.js)添加对您的 common 项目的引用并调用 init连接到 mongodb 服务器并注册模型的方法。

      //at the top, near your other module dependencies
      var mongoose = require('mongoose')
        , common = require('common');
      
      common.init(mongoose);
      
    7. 在您的应用程序中的任何地方使用模型 - 现在 mongoose 已经建立了连接池并且模型已经注册,您可以使用模型是您应用程序中的任何类。例如,假设您有一个显示有关user 信息的页面,您可以这样做(未经测试的代码,只是为了示例而编写的):

      var common = require('common');
      
      app.get('/user-profile/:id', function(req, res) {
          common.models.user.findById(req.params.id, function(err, user) {
               if (err)
                   console.log(err.message); //do something else to handle the error
               else
                   res.render('user-profile', {model: {user: user}});
          });
      });
      

    编辑 抱歉,我没有看到您从另一个模式继承一个模式的行。正如其他答案之一所述,猫鼬已经提供了plugin 的概念。在上面的示例中,您可以这样做:

    在您的公共模块中,在“/models/base-profile-plugin.js”下

    module.exports = exports = function baseProfilePlugin(schema, options){
    
        //These paths will be added to any schema that uses this plugin
        schema.add({
            _user: {type: Schema.Types.ObjectId, ref: 'User', required: true},
            name: {type: String, required: true},
            bio: {type: String, required: true},
            pictureLink: String
        });
    
        //you can also add static or instance methods or shared getter/setter handling logic here. See the plugin documentation on the mongoose website.
    }
    

    在您的公共模块中,在“/models/entrepreneur.js”下

    var mongoose    = require('mongoose')
      , basePlugin  = require('./base-profile-plugin.js');
    
    var entrepreneurSchema   = new mongoose.Schema({
        mentors: {type: Schema.Types.ObjectId, ref: 'Mentor'}
    });
    
    entrepreneurSchema.plugin(basePlugin);
    
    module.exports = mongoose.model('Entrepreneur', entrepreneurSchema);
    

    【讨论】:

    • 感谢您提供如此完整的答案。由于遇到了这个问题,我更倾向于这种类型的解决方案,它不需要我在模块之间共享模式。我仍然不知道为什么会出现问题,但我开始认为这是环境问题,也许一些缓存清除会有所帮助。
    • 我会接受这个答案 - 不是因为它实际上直接回答了我的问题,而是因为我认为它将它放在顶部将最能为社区服务。再次感谢您的努力。
    • 我并没有真正让它工作,并且不得不使用proxyquire 来覆盖我的架构定义模块中使用的 Mongoose 实例。有效,但看起来很脏。
    • 我不知道这在当时是否有效,但今天,如果你传入一个“mongoose”模块并对它执行“.connect()”,连接将是该模块的本地连接.因此,您在模型目录中定义的模型需要另一个“猫鼬”,但这个没有连接。因此,您在“init”中传入的 mongoose 将无法使用模型。
    • @tdecs 我也想知道这个。我来到这个线程并认为它对我也非常有用,但我得到了“MissingSchemaError:Schema还没有为模型注册”错误。你找到解决办法了吗?
    【解决方案2】:

    你为什么不为像这样https://github.com/Keeguon/mongoose-behaviors/blob/master/lib/timestampable.js这样的通用模式创建一个猫鼬插件

    【讨论】:

      【解决方案3】:

      您正在寻找的基本上是架构继承,有一个名为 mongoose extend 的项目实际上可以解决您的问题,您可以决定是否要实现它或查看代码并自己制作。

      只需使用 npm 安装它

      $ npm install mongoose-schema-extend
      

      这就是它的工作原理:

      var mongoose = require('mongoose'),
          extend = require('mongoose-schema-extend');
      var Schema = mongoose.Schema;
      
      var PersonSchema = new Schema({
        name : String
      }, { collection : 'users' });
      
      var EmployeeSchema = PersonSchema.extend({
        department : String
      });
      
      var Person = mongoose.model('Person', PersonSchema),
          Employee = mongoose.model('Employee', EmployeeSchema);
      
      var Brian = new Employee({
        name : 'Brian Kirchoff',
        department : 'Engineering'
      });
      

      问候

      【讨论】:

      • 这是一个非常有用的答案,但没有解决问题。在编辑中,您可以看到我遇到了非扩展架构的问题。我越来越相信这个问题是环境问题,但还没有机会在另一台机器上证明它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 2019-07-22
      相关资源
      最近更新 更多