Структура файла проекта Mongoose & NodeJS

В настоящее время у меня есть все мои модели (определения схемы) в файле /models/models.js для моего приложения Mongoose/NodeJS.

Я хотел бы разбить их на разные файлы: 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". *

Мысли?

Ответ 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

Другими словами, определите как схему, так и модель в модуле модели, а затем экспортируйте только модель. Загрузите модули модели в свои модули контроллера, используя относительные требуемые пути.

Чтобы сделать соединение, обработайте его на раннем этапе запуска вашего сервера (server.js или что-то еще). Обычно вам нужно будет прочитать параметры подключения либо из файла конфигурации, либо из переменных среды, и по умолчанию использовать режим развития localhost, если конфигурация не предоставляется.

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

Ответ 2

Пара ответов здесь действительно помогла мне разработать альтернативный подход. Исходный вопрос заключается в том, что он разбивает только определение схемы, но я предпочитаю связывать определения Схемы и Модели в том же файле.

Это в основном идея Питера, только экспорт определения модели путем переопределения 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'});

Не забудьте вызвать mongoose.connect(..) в server.js или где бы вы ни считали нужным!

Ответ 3

Недавно я ответил на вопрос Quora относительно этой же проблемы. http://qr.ae/RoCld1

То, что я нашел очень красивым и экономит на количестве вызовов require, состоит в том, чтобы структурировать ваши модели в один каталог. Убедитесь, что у вас есть только одна модель для каждого файла.

Создайте файл index.js в том же каталоге, что и ваши модели. Добавьте сюда этот код. Обязательно добавьте необходимые fs require

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.exports или require:

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