4

Is it possible to create new Meteor collections on-the-fly? I'd like to create foo_bar or bar_bar depending on some pathname which should be a global variable I suppose (so I can access it throughout my whole application).
Something like:

var prefix = window.location.pathname.replace(/^\/([^\/]*).*$/, '$1');
var Bar = new Meteor.Collection(prefix+'_bar');

The thing here is that I should get my prefix variable from URL, so if i declare it outside of if (Meteor.isClient) I get an error: ReferenceError: window is not defined. Is it possible to do something like that at all?

Edit : Using the first iteration of Akshats answer my project js : http://pastie.org/6411287

Tarang
  • 75,157
  • 39
  • 215
  • 276
errata
  • 5,695
  • 10
  • 54
  • 99
  • Even though it is possible, this doesn't mean it is a good idea: MongoDB has some limitations on the number of collections, it is not meant to scale by collection, so if your dynamic collections grow big, you might hit a wall. – MrE May 11 '16 at 22:22

2 Answers2

4

I'm not entirely certain this will work:

You need it in two pieces, the first to load collections you've set up before (on both the client and server)

var collections = {};
var mysettings = new Meteor.Collection('settings') //use your settings

//Startup
Collectionlist = mysettings.find({type:'collection'});

Collectionlist.forEach(function(doc) {
    collections[doc.name] = new Meteor.Collection(doc.name);
})'

And you need a bit to add the collections on the server:

Meteor.methods({
    'create_server_col' : function(collectionname) {
       mysettings.insert({type:'collection', name: collectionname});
       newcollections[collectionname] = new Collection(collectionname);
       return true;
    }
});

And you need to create them on the client:

//Create the collection:

Meteor.call('create_server_col', 'My New Collection Name', function(err,result) {
    if(result) {
        alert("Collection made");
    }
    else
    {
        console.log(err);
    }
}

Again, this is all untested so I'm just giving it a shot hopefully it works.

EDIT

Perhaps the below should work, I've added a couple of checks to see if the collection exists first. Please could you run meteor reset before you use it to sort bugs from the code above:

var collections = {};
var mysettings = new Meteor.Collection('settings')

if (Meteor.isClient) {
  Meteor.startup(function() {
    Collectionlist = mysettings.find({type:'collection'});

    Collectionlist.forEach(function(doc) {
        eval("var "+doc.name+" = new Meteor.Collection("+doc.name+"));
    });
  });
  Template.hello.greeting = function () {
    return "Welcome to testColl.";
  };

  var collectionname=prompt("Enter a collection name to create:","collection name")

  create_collection(collectionname);

  function create_collection(name) {
    Meteor.call('create_server_col', 'tempcoll', function(err,result) {
        if(!err) {
            if(result) {
                //make sure name is safe
                eval("var "+name+" = new Meteor.Collection('"+name+"'));
                alert("Collection made");
                console.log(result);
                console.log(collections);
            } else {
                alert("This collection already exists");
            }
        }
        else
        {
            alert("Error see console");
            console.log(err);
        }
    });
  }
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
    Collectionlist = mysettings.find({type:'collection'});

    Collectionlist.forEach(function(doc) {
        collections[doc.name] = new Meteor.Collection(doc.name);
    });
  });

  Meteor.methods({
    'create_server_col' : function(collectionname) {
       if(!mysettings.findOne({type:'collection', name: collectionname})) {
        mysettings.insert({type:'collection', name: collectionname});

        collections[collectionname] = new Meteor.Collection(collectionname);

        return true;
       }
       else
       {
        return false; //Collection already exists
       }
    }
  });
}

Also make sure your names are javascript escaped.

Tarang
  • 75,157
  • 39
  • 215
  • 276
  • Thanks for helping with this :) I've been playing around a bit with your code and I have noticed few things. First, I had to change few typos, my new code is [here](http://pastie.org/6411287). After running this, I can see the alert, so collection is obviously created, but when I try to query my new collection I get `ReferenceError: tempcoll is not defined`. Also after the alert appears, if I try to see my `collections` object in console, I see that it is empty. – errata Mar 07 '13 at 13:07
  • In the end, if I refresh the page with same collection name in my code, I get `Exception while invoking method 'create_server_col' Error: A method named '/tempcollx/insert' is already defined`. So I suppose I should check if collection with same name already exists somehow. I do believe that you were really close with your code, maybe there's something totally trivial, but I don't have so much experience with mongodb, so I'm not sure how to debug this further... Thanks for helping one more time :) – errata Mar 07 '13 at 13:09
  • If its ok with you i'm going to answer with your code you pasted, can I edit your question to include that link of your gist? – Tarang Mar 08 '13 at 13:55
  • There we go, sorry about the wait, this should be far closer to what you want – Tarang Mar 08 '13 at 18:15
3

Things got much easier:

var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
db.createCollection("COLLECTION_NAME", (err, res) => {
    console.log(res);
});

Run this in your server method.

Vlad Holubiev
  • 4,876
  • 7
  • 44
  • 59