【问题标题】:Dynamically create collection with Mongoose使用 Mongoose 动态创建集合
【发布时间】:2013-02-24 18:14:39
【问题描述】:

我想让用户能够在我的 Node 应用程序中创建集合。我真的只在猫鼬的集合中看到过硬编码的例子。任何人都知道是否可以使用猫鼬动态创建集合?如果是这样,一个例子会很有帮助。

基本上我希望能够将不同“事件”的数据存储在不同的集合中。

I.E. 事件: 事件1, 事件2, ... 事件N

用户可以在那里创建自己的自定义事件并将数据存储在该集合中。最后,每个事件可能有成百上千行。我想让用户能够对他们的事件执行 CRUD 操作。而不是存储在一个大集合中,我想将每个事件数据存储在不同的集合中。

我没有真正尝试过的示例,因为我只使用猫鼬创建了“硬编码”集合。我什至不确定是否可以根据用户请求在 mongoose 中创建一个动态的新集合。

var mongoose = require('mongoose');
mongoose.connect('localhost', 'events');

var schema = mongoose.Schema({ name: 'string' });
var Event1 = mongoose.model('Event1', schema);

var event1= new Event1({ name: 'something' });
event1.save(function (err) {
  if (err) // ...
  console.log('meow');
});

如果我将“Event1”硬编码为一个集合,上述方法效果很好。不确定我是否创建了动态集合。

var mongoose = require('mongoose');
mongoose.connect('localhost', 'events');

...

var userDefinedEvent = //get this from a client side request
...

var schema = mongoose.Schema({ name: 'string' });
var userDefinedEvent = mongoose.model(userDefinedEvent, schema);

你能做到吗?

【问题讨论】:

  • 您能否举例说明您想要做什么以及您已经尝试过什么?
  • 试图在原始问题中提供更多上下文。
  • 您展示的内容应该可以正常工作。您可以使用用户提供的字符串作为 mongoose 模型/集合名称。
  • 然后将这些集合名称存储在另一个“event_name”集合中,这样我就知道我想拥有哪些集合?感谢您的帮助,再次约翰尼!!!!

标签: node.js mongoose


【解决方案1】:

我试过Magesh varan参考代码,

这段代码对我有用

   router.post("/auto-create-collection", (req, res) => {
  var reqData = req.body; // {"username":"123","password":"321","collectionName":"user_data"}

  let userName = reqData.username;
  let passWord = reqData.password;
  let collectionName = reqData.collectionName;

  // create schema
  var mySchema = new mongoose.Schema({
    userName: String,
    passWord: String,
  });

  // create model
  var myModel = mongoose.model(collectionName, mySchema);

  const storeData = new myModel({
    userName: userName,
    passWord: passWord,
  });
  storeData.save();

  res.json(storeData);
});

【讨论】:

    【解决方案2】:

    是的,我们可以做到。我已经尝试过了,它的工作原理。

    参考代码:

    app.post("/",function(req,res){
    
      var Cat=req.body.catg;
      const link= req.body.link;
      const rating=req.body.rating;
      Cat=mongoose.model(Cat,schema);
      const item=new Cat({
      name:link,
      age:rating
      });
     item.save();
      res.render("\index");
    });
    

    【讨论】:

    • 是的,我试过它的作品
    【解决方案3】:

    这个方法最适合我,这个例子为每个用户创建动态集合,每个集合将只保存相应的用户信息(登录详细信息),首先在单独的文件中声明函数dynamicModel:example model.js

    /* model.js */
    'use strict';
    
    var mongoose = require('mongoose'),
      Schema = mongoose.Schema;
    
    
      function dynamicModel(suffix) {
          var addressSchema = new Schema(
              {
                   "name" : {type: String, default: '',trim: true},
                   "login_time" : {type: Date},
                   "location" : {type: String, default: '',trim: true},
              }
      );
    
         return mongoose.model('user_' + suffix, addressSchema);
    
      }
    
    module.exports = dynamicModel;
    

    在控制器文件示例 user.js 中,第一个函数用于创建动态集合,第二个函数用于将数据保存到特定集合

    /* user.js */
    var  mongoose = require('mongoose'),
    
    function CreateModel(user_name){//function to create collection , user_name  argument contains collection name
    
      var Model  = require(path.resolve('./model.js'))(user_name);
    
    }
    
    function save_user_info(user_name,data){//function to save user info , data argument contains user info
         var UserModel  = mongoose.model(user_name) ;
         var usermodel  = UserModel(data);
                  usermodel.save(function (err) {
    
                   if (err) {
                      console.log(err);
                    } else {
                     console.log("\nSaved");
                    }
               });
    }
    

    【讨论】:

      【解决方案4】:

      您可以尝试以下方法:

      var createDB = function(name) {
      
        var connection = mongoose.createConnection(
          'mongodb://localhost:27017/' + name);
      
        connection.on('open', function() {
          connection.db.collectionNames(function(error) {
            if (error) {
              return console.log("error", error)
            }
          });
      
        });
        connection.on('error', function(error) {
          return console.log("error", error)
        });
      
      }
      使用 connection.db.collectionNames 获取集合名称很重要,否则将不会创建数据库。

      【讨论】:

        【解决方案5】:

        来自 mongo 文档:数据建模

        在某些情况下,您可能会选择将信息存储在 多个集合而不是单个集合。

        考虑一个示例收集日志,用于存储日志文档 各种环境和应用。日志集合包含 以下形式的文件:

        { log: "dev", ts: ..., info: ... } { log: "debug", ts: ..., info: ...}

        如果文档总数较少,您可以将文档分组到 按类型收集。对于日志,考虑维护不同的日志 集合,例如 logs.dev 和 logs.debug。 logs.dev 集合 将仅包含与开发环境相关的文档。

        一般来说,拥有大量的集合并没有显着的意义 性能损失并导致非常好的性能。清楚的 集合对于高通量批处理非常重要。

        【讨论】:

        • @roel van uden 可能不是一个糟糕的主意!
        【解决方案6】:

        假设我有 20 个不同的事件。每个事件都有 100 万个条目......因此,如果这一切都在一个集合中,我将不得不为每个 CRUD 操作按事件过滤集合。

        我建议您将所有事件保存在同一个集合中,尤其是当事件名称取决于客户端代码并因此可能发生更改时。相反,索引名称和用户参考。

        mongoose.Schema({
          name: { type: String, index: true },
          user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true } 
        });
        

        此外,我认为您的问题有点倒退(但我可能弄错了)。您是在用户的上下文中查找事件,还是在事件名称的上下文中查找用户?我感觉是前者,你应该首先根据用户参考进行分区,而不是事件名称。

        如果您不需要查找用户的所有事件而只需要同时处理用户和事件名称,则可以使用复合索引:

        schema.index({ user: 1, name: 1 });
        

        如果您要处理数百万个文档,请务必关闭自动索引:

        schema.set('autoIndex', false);
        

        这篇文章有一些关于命名集合和使用特定架构的有趣内容:

        How to access a preexisting collection with Mongoose?

        【讨论】:

          【解决方案7】:

          我认为这是一个糟糕的想法,但一个问题值得回答。您需要定义一个具有动态名称的模式,该名称允许其中包含“任何”类型的信息。执行此操作的函数可能与此函数有点相似:

          var establishedModels = {};
          function createModelForName(name) {
              if (!(name in establishedModels)) {
                  var Any = new Schema({ any: Schema.Types.Mixed });
                  establishedModels[name] = mongoose.model(name, Any);
              }
              return establishedModels[name];
          }
          

          现在您可以创建允许信息不受任何限制(包括名称)的模型。我将假设一个像这样定义的对象{name: 'hello', content: {x: 1}},它是由“用户”提供的。为了保存它,我可以运行以下代码:

          var stuff = {name: 'hello', content: {x: 1}}; // Define info.
          var Model = createModelForName(name); // Create the model.
          var model = Model(stuff.content); // Create a model instance.
          model.save(function (err) { // Save
              if (err) {
                  console.log(err);
              }
          });
          

          查询非常相似,获取模型然后进行查询:

          var stuff = {name: 'hello', query: {x: {'$gt': 0}}}; // Define info.
          var Model = createModelForName(name); // Create the model.
          model.find(stuff.query, function (err, entries) {
              // Do something with the matched entries.
          });
          

          您必须实施代码来保护您的查询。您不希望用户炸毁您的数据库。

          【讨论】:

          • 你说这是一个糟糕的主意,但别无选择。假设我有 20 个不同的事件。每个事件有 100 万个条目。您必须提供要查询的事件。因此,如果这一切都在一个集合中,我将不得不为每个 CRUD 操作按事件过滤集合。我想我可以通过将每个事件存储在自己的集合中来节省这一点。这样,当用户对事件进行 CRUD 操作时,我可以直接进入该事件集合,绕过其他 1900 万个条目。如果有人有其他想法,我绝对会全力以赴,非常感谢您的帮助。
          • 只是做一个索引?这就是我们有索引的原因。此外,提出替代方案并不是回答问题的工作。这是为了回答提出的问题。
          • 您的问题的答案已经提供。如果您使用单个集合并希望允许 CRUD 操作,则只需跟踪所有权。您可以通过存储 _id 在用户中创建一个拥有事件文档的数组。然后,所有 CRUD 操作都可以在不影响性能的情况下进行,无论文档数量如何(即使有 1900 万以上,数据库也不会关心)。
          猜你喜欢
          • 1970-01-01
          • 2021-05-29
          • 2016-05-02
          • 2020-03-20
          • 1970-01-01
          • 2020-11-11
          • 2014-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多