【问题标题】:Call require on mongoose model more than once多次调用 mongoose 模型的 require
【发布时间】:2021-03-17 09:52:42
【问题描述】:

我在猫鼬中的模型定义如下:

user.js

module.exports = function() {
  var mongoose = require('mongoose');

  // Creates a new Mongoose Schema object
  var Schema = mongoose.Schema; 

  // Collection to hold users
  var UserSchema = new Schema({
      username: { type: String, required: true },
      password: { type: String, required: true },
    },{ 
      versionKey: false 
    }
  );

  // Creates the Model for the User Schema
  var User = mongoose.model('User', UserSchema);

  var getUserById = function(id, callback) {
    User.findById(id, callback);
  }

  var getUserByUsername = function(username, callback) {
    var query = {username: username};
    User.findOne(query, callback);
  }


  return {
    getUserById: getUserById,
    getUserByUsername: getUserByUsername
  }
}()

基本上,我返回的是用户模型的客户端可以使用的公共接口。 IE。我的用户路线抓取模型,可以调用定义的两个公共方法,仅此而已。我这样做是为了从我的路线中抽象出我正在使用 mongodb/mongoose 的事实。我很可能会在某个时候拥有一个与 postgres 对话的用户模型,或者可能只是切换到 postgres。因此,我不想通过代码查看调用特定于猫鼬的函数的路由方法中的位置。

这是我的问题。当我需要一个我调用的模块时,代码中的大多数地方

var someUtil = require('./someUtil');

但是,如果我对 mongoose 模型多次执行此操作,我会收到一条错误消息,指出它不能定义两次。

var User = require('./user');  // Cannot put this in more than one file without getting an error.

是否有更好的方法来编写 user.js 文件,这样我可以为我的用户模型提供一个公共接口,但只定义一次架构,以便我可以在该文件上多次调用 require ?

【问题讨论】:

  • AFAIK 节点缓存需要模块的结果,因此上述函数不应运行两次。除此之外,没有理由将代码包装在自执行函数中,只需公开exports.getUserById = getUserById; //etc 之类的方法即可。

标签: node.js mongoose


【解决方案1】:

您应该将 Mongoose 模型与您包装它的服务分开。

我建议你有一个模型文件夹,每个架构有 1 个文件,每个文件看起来有点像这样:

'use strict';

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

var User = new Schema({
    ...fields your schema will have
})

//additional virtuals or configuration

module.exports = mongoose.model('User', User)

然后有一个 services 文件夹,其中包含需要该模型的 UserService:

var User = require('../models/User')

function UserService(){
    //create User, delete User, etc.
}

module.exports = new UserService()

那么从现在开始,您的控制器或路由只需要 UserService。您不会遇到此类问题,并且您的代码更有条理。

【讨论】:

    【解决方案2】:

    我也遇到过这个问题。

    您可以做的是将架构定义包装在 try catch 中

    将此行var User = mongoose.model('User', UserSchema); 替换为:

    var User;
    try {
      User = mongoose.model('User', UserSchema);
    }
    catch(e) {
      User = mongoose.model('User');
    }
    

    不确定它是否是最好的方法,但它会起作用。

    【讨论】:

      【解决方案3】:

      安德烈亚斯是正确的:

      AFAIK node caches the result of requireing a module, and thus the above function should not be run twice. Other than that there's no reason to wrap you code in a self-executing function, just expose the methods like exports.getUserById = getUserById; //etc.
      

      【讨论】:

        【解决方案4】:

        我遇到了这个问题,我想我会贡献我的答案。我遇到的问题稍微复杂一些,因为我的模式中有“参考”定义。我还没有完全理解“为什么”,但基本上正在发生的事情是依赖链导致节点两次需要相同的文件。这是经过验证的,因为我得到了两次 console.log 输出。我以前的方法是简单地导出模式而不是模型,但这很烦人,因为我必须在执行开始时引导所有模型。经过一番修修补补,我选择了这个范式(使用 coffeescript):

        Mongoose = require 'mongoose'
        
        unless 'Foo' in Mongoose.modelNames()
          schema = new Mongoose.Schema
            bar: String
          Mongoose.model 'Foo', schema
        
        module.exports = Mongoose.model 'Foo'
        

        【讨论】:

          【解决方案5】:

          在你定义 express 的 index.js 顶部的其他任何东西之前,你只需要一次 mongoose 模型:

          require('./models/User');
          const express = require('express');
          

          然后在应用程序的其他部分,您可以通过以下方式访问此模型:

          const mongoose = require('mongoose');
          const User = mongoose.model('User');
          

          由于我们需要 index.js 中的模型,因此执行了这行代码:mongoose.model('User', userSchema),现在可以在应用程序的任何位置访问它

          【讨论】:

            猜你喜欢
            • 2015-12-13
            • 1970-01-01
            • 2015-11-19
            • 2020-05-17
            • 2016-02-06
            • 2013-10-07
            • 2016-06-09
            • 2015-01-08
            • 1970-01-01
            相关资源
            最近更新 更多