web-dev-qa-db-fra.com

Structure des fichiers du projet JS Mongoose et Node

J'ai actuellement tous mes modèles (définitions de schéma) dans le fichier /models/models.js pour mon application Mongoose/NodeJS.

Je voudrais les séparer en différents fichiers en tant que tels: user_account.js, profile.js, etc. Cependant, je ne peux pas sembler le faire car mes contrôleurs se brisent et rendent compte "impossible de trouver le module" une fois que je séparer ces classes.

La structure de mon projet est la suivante:

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

Le contenu de mon fichier models.js ressemble à ceci:

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

Mon fichier user.js (contrôleur) ressemble à ceci:

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?! :)
}

Comment puis-je diviser la définition de schéma en plusieurs fichiers et également la référencer depuis mon contrôleur? Lorsque je le référence (après que le schéma se trouve dans un nouveau fichier), j'obtiens cette erreur:

* Erreur: le schéma n'a pas été enregistré pour le modèle "compte_utilisateur". *

Pensées?

57
Donn Felker

Voici un exemple 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
}

Pour le charger à partir d'un contrôleur d'élément dans app/controllers/items.js Je ferais

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

En d'autres termes, définissez à la fois le schéma et le modèle dans votre module de modèle, puis exportez uniquement le modèle. Chargez vos modules de modèle dans vos modules de contrôleur en utilisant des chemins d'accès relatifs.

Pour établir la connexion, gérez-le au début du code de démarrage de votre serveur (server.js ou peu importe). Habituellement, vous souhaiterez lire les paramètres de connexion à partir d'un fichier de configuration ou de variables d'environnement et par défaut en mode de développement localhost si aucune configuration n'est fournie.

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

Quelques réponses ici m'ont vraiment aidé à développer une approche alternative. La question d'origine concerne la rupture juste de la définition de schéma, mais je préfère regrouper les définitions de schéma et de modèle dans le même fichier.

C'est principalement l'idée de Peter, exporter uniquement la définition du modèle en remplaçant module.exports pour rendre l'accès au modèle à partir de votre contrôleur un peu moins détaillé:

Disposition du projet:

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

models/Item.js ressemblerait à:

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

Et vous accédez au modèle dans un contrôleur, par exemple user.js, comme:

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

...

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

N'oubliez pas d'appeler mongoose.connect (..) dans server.js, ou partout où vous le jugez approprié!

35
Nick Boyle

J'ai récemment répondu à une question Quora concernant ce même problème. http://qr.ae/RoCld1

Ce que j'ai trouvé très agréable et économise sur le nombre d'appels requis , c'est de structurer vos modèles dans un seul répertoire. Assurez-vous de n'avoir qu'un seul modèle par fichier.

Créez un fichier index.js dans le même répertoire que vos modèles. Ajoutez-y ce code. Assurez-vous d'ajouter le nécessaire fs requis

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

Vous pouvez maintenant appeler tous vos modèles comme suit:

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

Peter Lyons a à peu près couvert la base.
Empruntant de l'exemple ci-dessus (en supprimant les lignes après le schéma), je voulais juste ajouter:

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
  },
  ...

});

Pour le charger à partir du app/controllers/items.js

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

Une autre façon sans le module.exports ou 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

Dans le app/controllers/items.js

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

Inspiré par sequelize-cli, j'ai un répertoire de modèles où je définis tous les schémas.

Application complète sur 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: {
    }
};
1
Varun Kumar