Dynamically create collection with Mongoose

From mongo docs here: data modeling

In certain situations, you might choose to store information in several collections rather than in a single collection.

Consider a sample collection logs that stores log documents for various environment and applications. The logs collection contains documents of the following form:

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

If the total number of documents is low you may group documents into collection by type. For logs, consider maintaining distinct log collections, such as logs.dev and logs.debug. The logs.dev collection would contain only the documents related to the dev environment.

Generally, having large number of collections has no significant performance penalty and results in very good performance. Distinct collections are very important for high-throughput batch processing.


I believe that this is a terrible idea to implement, but a question deserves an answer. You need to define a schema with a dynamic name that allows information of 'Any' type in it. A function to do this may be a little similar to this function:

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

Now you can create models that allow information without any kind of restriction, including the name. I'm going to assume an object defined like this, {name: 'hello', content: {x: 1}}, which is provided by the 'user'. To save this, I can run the following code:

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

Queries are very similar, fetch the model and then do a query:

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

You will have to implement code to protect your queries. You don't want the user to blow up your db.


Say I have 20 different events. Each event has 1 million entries... As such if this is all in one collection I will have to filter the collection by event for every CRUD op.

I would suggest you keep all events in the same collection, especially if event names depend on client code and are thus subject to change. Instead, index the name and user reference.

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

Furthermore I think you came at the problem a bit backwards (but I might be mistaken). Are you finding events within the context of a user, or finding users within the context of an event name? I have a feeling it's the former, and you should be partitioning on user reference, not the event name in the first place.

If you do not need to find all events for a user and just need to deal with user and event name together you could go with a compound index:

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

If you are dealing with millions of documents, make sure to turn off auto index:

schema.set('autoIndex', false);

This post has interesting stuff about naming collections and using a specific schema as well:

How to access a preexisting collection with Mongoose?