【问题标题】:File Structure of Mongoose & NodeJS ProjectMongoose 和 Node JS 项目的文件结构
【发布时间】:2012-03-03 02:36:01
【问题描述】:

目前,我的 Mongoose/NodeJS 应用程序的 /models/models.js 文件中包含我的所有模型(架构定义)。

我想将它们分成不同的文件,例如:user_account.js、profile.js 等。但是我似乎无法这样做,因为我的控制器中断并报告“找不到模块强>”一旦我把这些类分开。

我的项目结构如下:

/MyProject
  /controllers
    user.js
    foo.js
    bar.js
    // ... etc, etc
  /models
    models.js
  server.js

我的 models.js 文件的内容如下所示:

var mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

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

var UserAccount = new Schema({
    user_name       : { type: String, required: true, lowercase: true, trim: true, index: { unique: true } }, 
    password        : { type: String, required: true },
    date_created    : { type: Date, required: true, default: Date.now }
}); 

var Product = new Schema({
    upc             : { type: String, required: true, index: { unique: true } },
    description     : { type: String, trim: true },
    size_weight     : { type: String, trim: true }
});

我的 user.js 文件(控制器)如下所示:

var mongoose    = require('mongoose'), 
    UserAccount = mongoose.model('user_account', UserAccount);

exports.create = function(req, res, next) {

    var username = req.body.username; 
    var password = req.body.password;

    // Do epic sh...what?! :)
}

如何将架构定义分解为多个文件并从我的控制器中引用它?当我确实引用它时(在架构位于新文件中之后)我收到此错误:

*错误:尚未为模型“user_account”注册架构。*

想法?

【问题讨论】:

标签: node.js mongoose


【解决方案1】:

这是一个示例app/models/item.js

var mongoose = require("mongoose");

var ItemSchema = new mongoose.Schema({
  name: {
    type: String,
    index: true
  },
  equipped: Boolean,
  owner_id: {
    type: mongoose.Schema.Types.ObjectId,
    index: true
  },
  room_id: {
    type: mongoose.Schema.Types.ObjectId,
    index: true
  }
});

var Item = mongoose.model('Item', ItemSchema);

module.exports = {
  Item: Item
}

要从 app/controllers/items.js 中的项目控制器加载它,我会这样做

  var Item = require("../models/item").Item;
  //Now you can do Item.find, Item.update, etc

换句话说,在模型模块中定义模式和模型,然后只导出模型。使用相对的 require 路径将模型模块加载到控制器模块中。

要建立连接,请在服务器启动代码的早期处理它(server.js 或其他)。通常你会希望从配置文件或环境变量中读取连接参数,如果没有提供配置,则默认为开发模式 localhost。

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost');

【讨论】:

  • 连接码呢?如何将其包含在单独的代码中
  • 这仍然是一个有效的解决方案吗?
  • @PeterLyons @taco 由于已编译的模型缓存,我在使用此解决方案时遇到问题:OverwriteModelError(v3.8.17 中的猫鼬/lib/index.js@@334)。建议的解决方法是设置var ItemSchema = mongoose.modelSchemas['Item'] || new mongoose.Schema({...});(对我有用)
  • 你为什么要定义你的模式两次?该代码应该每个进程只运行一次。
  • 当模式被编译时,它会添加一些额外的东西(_events 对象和 __virtual 和其他一些东西),所以在 index.js 与缓存模式的比较中,它与OverwriteModelError 相比失败了。每次请求模块时都会传递架构,我不知道为什么,也许它是一个调试功能或者我仍然没有找到原因......(模块的实现方式与您在此处提出的相同方式只是更改名称和字段)
【解决方案2】:

这里的几个答案确实帮助我开发了另一种方法。最初的问题是关于打破just Schema 定义,但我更喜欢将 Schema 和 Model 定义捆绑在同一个文件中。

这主要是 Peter 的想法,仅通过覆盖 module.exports 来导出模型定义,以使从控制器中访问模型变得不那么冗长:

项目布局:

MyProject
  /controllers
    user.js
    foo.js
    bar.js
    // ... etc, etc
  /models
    Item.js
  server.js

models/Item.js 看起来像:

var mongoose = require("mongoose");

var ItemSchema = new mongoose.Schema({
  name: {
    type: String,
    index: true
  }
});

module.exports = mongoose.model('Item', ItemSchema); 
// Now `require('Item.js')` will return a mongoose Model,
// without needing to do require('Item.js').Item

然后你在控制器中访问模型,比如 user.js,比如:

var Item = require(__dirname+'/../models/Item')

...

var item = new Item({name:'Foobar'});

不要忘记在 server.js 或其他您认为合适的地方调用 mongoose.connect(..)!

【讨论】:

    【解决方案3】:

    我最近回答了一个关于这个问题的 Quora 问题。 http://qr.ae/RoCld1

    我发现非常好的并节省 require 调用量的方法是将模型构建到单个目录中。确保每个文件只有一个模型。

    在与模型相同的目录中创建一个 index.js 文件。将此代码添加到其中。请务必添加必要的 fs 要求

    var fs = require('fs');
    
    /*
     * initializes all models and sources them as .model-name
     */
    fs.readdirSync(__dirname).forEach(function(file) {
      if (file !== 'index.js') {
        var moduleName = file.split('.')[0];
        exports[moduleName] = require('./' + moduleName);
      }
    });
    

    现在您可以按如下方式调用所有模型:

    var models = require('./path/to/models');
    var User = models.user;
    var OtherModel = models['other-model'];
    

    【讨论】:

    • 这是迄今为止最好的答案,自动化在代码中节省了大量冗余,而且最终看起来非常干净。
    • 我假设你在项目根目录中有你的数据库初始化代码。知道这是如何执行的吗?谢谢
    【解决方案4】:

    彼得里昂几乎涵盖了基础。
    借用上面的例子(删除模式后的行)我只想添加:

    app/models/item.js

    note: notice where `module.exports` is placed
    var mongoose = require("mongoose");
    
    var ItemSchema = module.exports = new mongoose.Schema({
      name: {
        type: String,
        index: true
      },
      ...
    
    });
    

    app/controllers/items.js加载它

    var mongoose = require('mongoose');
    var Item = mongoose.model('Item', require('../models/item'));  
    

    没有module.exportsrequire 的另一种方式:

    app/models/item.js

    var mongoose = require("mongoose");
    
    var ItemSchema = new mongoose.Schema({
      name: {
        type: String,
        index: true
      },
      ... 
    
    });
    
    mongoose.model('Item', ItemSchema); // register model
    

    app/controllers/items.js

    var mongoose = require('mongoose')
      , Item = mongoose.model('Item');  // registered model
    

    【讨论】:

    • 从哪里调用控制器?
    • 不确定我是否理解您的问题。你能澄清一下吗?
    【解决方案5】:

    受 sequelize-cli 的启发,我有一个模型目录,我在其中定义了所有模式。

    github上的完整应用:https://github.com/varunon9/node-starter-app-mongo

    models/index.js-

    'use strict';
    
    const fs        = require('fs');
    const path      = require('path');
    const mongoose = require('mongoose');//.set('debug', true);
    const basename  = path.basename(__filename);
    const env       = process.env.NODE_ENV || 'development';
    const config    = require(__dirname + '/../config/config.json')[env];
    const db        = {};
    
    const Schema = mongoose.Schema;
    
    fs
        .readdirSync(__dirname)
        .filter(fileName => {
            return (
                fileName.indexOf('.') !== 0) 
                        && (fileName !== basename) 
                        && (fileName.slice(-3) === '.js'
            );
        })
        .forEach(fileName => {
            const model = require(path.join(__dirname, fileName));
            const modelSchema = new Schema(model.schema);
    
            modelSchema.methods = model.methods;
            modelSchema.statics = model.statics;
    
            // user.js will be user now
            fileName = fileName.split('.')[0];
            db[fileName] = mongoose.model(fileName, modelSchema);
        });
    
    module.exports = db;
    

    models/user.js-

    'use strict';
    
    module.exports = {
        schema: {
            email: {
                type: String,
                required: true,
                unique: true,
            },
            mobile: {
                type: String,
                required: false
            },
            name: {
                type: String,
                required: false
            },
            gender: {
                type: String,
                required: false,
                default: 'male'
            },
            password: {
                type: String,
                required: true
            },
            dob: {
                type: Date,
                required: false
            },
            deactivated: {
                type: Boolean,
                required: false,
                default: false
            },
            type: {
                type: String,
                required: false
            }
        },
    
        // instance methods goes here
        methods: {
    
        },
    
        // statics methods goes here
        statics: {
        }
    };
    

    【讨论】:

      【解决方案6】:

      我喜欢用类来组织一切,不妨试试这个:

      const mongoose = require('mongoose')
      
      class UserAccount {
          constructor() {
              this.schema = new mongoose.Schema({
                  user_name: { type: String, required: true, lowercase: true, trim: true, index: { unique: true } },
                  password: { type: String, required: true },
                  date_created: { type: Date, required: true, default: Date.now }
              });
              this.model = new mongoose.model('UserAccount', this.schema)
          }
      
          create = (obj) => {
              return new Promise((resolve, reject) => {
                  this.model.create({ ...item })
                      .then((result) => {
                          resolve(result)
                      }).catch((err) => {
                          reject(err)
                      });
              });
          }
      }
      
      module.exports = UserAccount;
      
      

      这种方法允许您添加自定义方法。此外,它将控制器/模型组合成一个向量,允许您随时分离模型。这可能无法在企业中扩展,但它可能适合较小的应用程序。

      【讨论】:

        猜你喜欢
        • 2017-05-22
        • 2016-06-25
        • 1970-01-01
        • 2019-02-01
        • 2023-03-21
        • 2013-04-13
        • 2014-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多