Per customer databases?


#1

Last year I completed a Meteor app for a client and it was accepted into the AppStore. The client is marketing the app, but many of his potential customers are concerned with data security are have requested to let their own in-house IT departments manage the data. Since this app uses a conventional configuration, all of the current customer data is shared within a single database. I would appreciate any suggestions on how to address this request. Thanks in advance.


#2

Hi there,

The most efficient way to do this, albeit a bit more expensive, is to deploy a new instance of your app every time a new database is needed.


#3

Thanks for the prompt reply. I agree and had originally suggested this to my client. I think your suggestion is a lot more straightforward than trying to configure the database on a per-customer basis, which essentially presents a chicken-or-egg problem since Meteor needs the db name up front to connect.


#4

Actually, I just thought of one glitch. Once the app is deployed to the server, how do I distribute this customized version to their iOS users since our current one-size-fits-all version is submitted via the AppStore?


#5

You require an enterprise developer license. So you can roll out company wide:

https://developer.apple.com/programs/enterprise/

There are also other tools for doing enterprise roll out.

Search for: mobile device management

Those tools allow you to manage settings like VPN, mail, apps for all company mobile devices

If you have an enterprise customer they might already use that solution.


#6

It seems a bit fiddly but it’s possible to get the same app to connect to different Meteor servers. So you could have a login menu where the user selects which company to log in to (maybe by typing in the company name or url, in case your customers would feel weird being listed together).


#7

You could technically have the Meteor client connect to various servers. It would look something like:
1- App connects to central server, and gets the details of the server that it should connect to
2- App disconnects from central server
3- App reconnects to whatever server is necessary

I believe the API you would be looking for is DDP.connect()


#8

@chipcastle This is possible without having to have a new instance of your app for every customer, but you would lose the benefits of Meteor’s Mongo.Collection functions, because all of Meteor’s built-in db calls rely on a global MONGO_URL env var. Unfortunately, to my knowledge, the only way right now to retain all Meteor functionality while supporting multiple customer databases would be to have separate app instances for each customer, and each instance has it’s own unique MONGO_URL pointing to that customer’s db. That’s totally possible and not too complicated, but it is very expensive to scale and it could be more trouble than it’s worth, depending on your situation.

If you want to go the former, less expensive but more janky route, you can use node’s native mongodb driver separately from Meteor for all your db operations, and each time you perform a db call, you use a dynamic per-customer mongo_url field that you store in your users collection, for example. When the customer creates an account on your system, have them provide the url and credentials to their MongoDB instance. Therefore, the only data you need to store on your servers is user data. You’d also need to provide some sort of public API docs so that they know what kind of data your system supports. However, storing the mongo_url for each customer is the core concept.

When implementing your methods, depending on the user and what “customer group” they belong to, you can make the calls using the customer’s mongo_url that you have stored in your own db. This allows you to host identical production instances of your app that you can scale as needed without having to manage separate instances for each customer. It also saves you tons of space since you don’t need to host your all customers’ data. If you have a lot high frequency reads and you’re worried about speed, I’d suggest caching your customers’ data on your system with something like redis.

That’s the jist of it.


#9

@herteby - Thanks for the suggestion. By “Meteor servers” do you mean separate instances of the app? Would this be a separate app that acts as a gateway to the main app?


#10

@msavin - DDP.connect() sounds interesting, but wouldn’t I need to know the customer id (or subdomain) before connecting?


#11

Thanks @weissi8! I’ll take a look.


#12

What I meant was that each “Meteor server” is a full copy of the project. For the web version you could just set them up completely independently (what I’ve done is give each company it’s own subdomain). But to avoid having to release one app for each on the App Store, you make it so that on the login screen the user can choose, and then you use DDP.connect() as @msavin said to change the connection of your app to one of the servers.


#13

You can choose which database a Collection uses like this:

if(Meteor.isServer){
	Shared = new MongoInternals.RemoteCollectionDriver('mongodb://localhost:27017/shared?replicaSet=rs0',{oplogUrl:'mongodb://localhost:27017/local?authSource=shared'});
} else {
	Shared = undefined;
}
Documents = new Mongo.Collection('documents', {_driver:Shared}); //Setting _driver on the client doesn't do anything

#14

Heyyyyy there you go! I didn’t know that, that’s pretty sweet :slight_smile:


#15

Nice! Using DDP is definitely an interesting option for connecting to a small customer/user database that my client manages internally. I’m not sure how my client would feel about having the user choose the company, but as you mentioned having a subdomain might circumvent that issue altogether. I wasn’t aware of MongoInternals.RemoteCollectionDriver, so that is very much appreciated as well! Thank you.


#16

We could probably get away with using a single copy/instance of the app as well if I follow that approach. My main issue with using a separate copies that maintenance will become very cumbersome, but it is still an option.


#17

I just run all instances on the same server, launched from the same app.js file, just different environment vars :slight_smile: It’s a bit wasteful with RAM I guess, but this way I can use all four cores, and I could easily move them to separate servers if scaling became an issue.


#18

Having multiple copies is something to keep in mind for future growth. We’re on a small server now, so I’ll probably go with the single copy at first. If the number of customers we serve grows by a large amount, having remote databases will ease the pain somewhat if I need to separate the instances or put on other servers. Thanks again for all of your suggestions. Great stuff!


#19

Reasonably speaking - how many database connections do you think a Meteor app can keep open?


#20

I don’t know. I would need to do further research.