Mongodb - document vs subdocument?

So as Meteor devs, I’d be interested to hear how you structure your MongoDB data so that you keep things as flexible as possible whilst also allowing the right data to be reactive.

One of the things I always struggle with is deciding what should fit as a sub document and what should fit as a document.

So for example, say in my application there are Teams and Players. One team has many players and in SQL would probably be two tables linked by a foreign key. The application only has two screens - a screen listing all the teams and a team detail screen which lists all the players in the team.

So in this simple example, I would probably make Team a collection but do I make Players a collection on its own or a sub collection of Teams?

If I make Players a sub-collection, then when I subscribe to my Team document, I automatically get all the Players within.

However, if I make Players a sub collection of Teams, I’m also creating a data structure that’s severely limiting. So for example, if a new requirement was for a function that allowed the user to search all the players in the system, that would be very hard to do if all players were inside Teams as I would need to search within all teams.

So without knowing the future (and let’s face it, you never know the future) how do I decide what should be a document and what should be a sub document? The SQL way would be to make Team and Players its own table. That gives you maximum flexibility but if I did that, then that’s not taking advantage of Mongodb, my MongoDB db will just be a relational database where I would need to manually handle all of the relationships. So in this case, I would need to create another publication PlayerInTeam(teamId) for the Player / Team join and subscribe to it.

I know MongoDb is probably really good for Big Data type use cases but in the context of a Meteor web app, how do you guys handle structuring your data?

You have to factor in how data protocol (DDP) in Meteor works. DDP works on a document level, it sends over the wire changes that happen to all top-level fields in a document. So if you store Player objects inside Team object, DDP will transfer whole Player array to the client every time anything changes in any Player object for that Team, which wastes bandwidth.

So in this case you should just have two separate collections and have a “foreign key”-like property on either that links to the ID of another, like in relational DBs. Then you can use publishComposite if you want to publish them together.

I personally store only small bits of data in subdocuments, where I know there will not be many subdocument items. emails, services and profile properties on Meteor.users collection are good examples.

Edit: See also Collections and Schemas - denormalization section from the Meteor Guide for some more helpful information.

Edit 2: @tomRedox beat me to it :slight_smile:

1 Like

@M4v3R covers it really well, but there is also more on this in the Meteor Guide in case you haven’t already seen it: http://guide.meteor.com/collections.html#schema-design