Nodejs 有没有办法从内存或者mongodb中require一个文件?

Nodejs 有没有办法从内存或者mongodb中require一个文件?

比如说,我在一个项目中有很多动态生成的代码(例如mongoose的schema)。现在我希望把这些代码存到mongodb中,然后需要的时候再读出来并require。

也就是说,被require这段代码并不在实际的物理路径上,而是内存中或者数据库中。

我大概希望的是这样,类似下面的代码,js代码(doc.content)是存在mongodb中的,读取数据库,再require这段代码。

model.findOne({}, function(err, doc){
   var mod = require(doc.content)
})

诸位,有什么好建议?


4 回复

当然可以!在Node.js中,你可以通过将代码字符串动态编译为模块来实现从内存或MongoDB中加载代码。下面是一个简单的示例,展示如何从MongoDB中读取JavaScript代码,并将其动态加载为模块。

示例代码

  1. 安装必要的库

    npm install mongoose
    
  2. 定义Mongoose模型和连接数据库

    const mongoose = require('mongoose');
    
    // 连接到MongoDB
    mongoose.connect('mongodb://localhost:27017/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true });
    
    // 定义存储代码的Schema
    const codeSchema = new mongoose.Schema({
        name: String,
        content: String
    });
    
    const CodeModel = mongoose.model('CodeModel', codeSchema);
    
  3. 插入示例代码到MongoDB

    const exampleCode = `
    module.exports = {
        hello: function() {
            console.log('Hello from dynamic code!');
        }
    };
    `;
    
    const codeDoc = new CodeModel({ name: 'example', content: exampleCode });
    codeDoc.save().then(() => console.log('Code saved!'));
    
  4. 从MongoDB中读取并执行代码

    const util = require('util');
    const vm = require('vm');
    
    async function loadDynamicCode() {
        try {
            const doc = await CodeModel.findOne({ name: 'example' }).exec();
            if (doc) {
                // 使用vm模块执行代码
                const script = new vm.Script(doc.content);
                const context = {
                    module: {},
                    exports: {}
                };
    
                script.runInNewContext(context);
    
                // 导出模块
                return context.exports;
            } else {
                console.error('Code document not found.');
            }
        } catch (err) {
            console.error('Error loading dynamic code:', err);
        }
    }
    
    loadDynamicCode().then((mod) => {
        if (mod) {
            mod.hello(); // 输出 "Hello from dynamic code!"
        }
    });
    

解释

  1. 定义Mongoose模型:我们创建了一个CodeModel模型,用于存储代码内容。
  2. 插入示例代码:我们将一段简单的代码插入到MongoDB中。
  3. 从MongoDB中读取代码:使用findOne方法从MongoDB中读取代码。
  4. 动态执行代码:使用vm模块执行从MongoDB中读取的代码。vm模块允许你在安全的环境中运行代码。
  5. 导出模块:将执行后的结果导出为模块,并调用其中的方法。

这种方法允许你动态地从MongoDB中加载和执行代码,非常适合处理动态生成的代码(如Mongoose schema等)。


给你看看下面的代码:

// node.js require js的处理
Module._extensions['.js'] = function(module, filename) {
  var content = NativeModule.require('fs').readFileSync(filename, 'utf8');
  module._compile(stripBOM(content), filename);
}

// coffee-script 增加到coffee的处理 loadFile = function(module, filename) { var raw, stripped;

raw = fs.readFileSync(filename, ‘utf8’); stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw; return module._compile(compile(stripped, { filename: filename, literate: helpers.isLiterate(filename) }), filename); };

if (require.extensions) { _ref = [’.coffee’, ‘.litcoffee’, ‘.coffee.md’]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { ext = _ref[_i]; require.extensions[ext] = loadFile; } }

本质就是去扩展一下require方法,让它对某个特定的后缀作处理,node.js的代码在源码中的module.js,coffee的在coffee-script.js中,自己去参考一下。

要实现从内存或MongoDB中动态加载代码(例如Mongoose schema),你可以使用一些辅助库来完成这项任务。Node.js本身并没有直接支持这种操作的功能,但可以利用一些间接的方法来实现。

示例方法

  1. 从内存中加载代码

如果你已经将代码存储在内存中,你可以使用new Function()构造函数来创建一个函数,并执行其中的代码。

const code = `
module.exports = {
    name: 'dynamicSchema',
    schema: {
        field: String
    }
};
`;

// 创建一个新的函数并立即执行
const dynamicModule = new Function(`return ${code}`)();
console.log(dynamicModule.name); // 输出: dynamicSchema

这种方法虽然简单,但它并不能直接提供模块化功能。

  1. 从MongoDB中加载代码

如果你希望从MongoDB中获取并执行代码,首先需要从数据库中读取代码字符串,然后通过上述方式执行它。

const mongoose = require('mongoose');

// 假设你已经配置好了Mongoose连接
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true });

const codeSchema = new mongoose.Schema({
    content: String,
});

const CodeModel = mongoose.model('Code', codeSchema);

async function loadDynamicCode() {
    const doc = await CodeModel.findOne({});
    if (!doc) throw new Error('No document found');
    
    const codeString = doc.content;
    const dynamicModule = new Function(`return ${codeString}`)();
    
    console.log(dynamicModule.name); // 动态输出内容
}

loadDynamicCode();

解释

  • 使用mongoose连接到MongoDB,并定义了一个简单的模式来存储代码。
  • 当你需要加载动态代码时,查询MongoDB获取代码字符串。
  • 使用new Function()来执行该字符串,从而将其转换为模块。

这种方法的优点是它可以灵活地处理来自数据库的动态代码。缺点是它不是完全模块化的,依赖于手动解析代码结构。

如果需要更高级的功能,例如模块间的依赖关系、错误处理等,可能需要进一步扩展或使用其他库来帮助管理动态加载的代码。

回到顶部