Defining schemas for 2 models in `many-to-many` relationship


#1

I’m thinking to implement many-to-many relations with post and tag.

In Meteor, with one-to-many relation, like post has many comments, comments collection has field "postId" : "h9dCsAfR4uqWHpXNH", that shows to which post a given comment belong. At the same time posts collection don’t have any informations about comments.

In my opinion, with many-to-many relations we’ll have different approach.

My thought is as follows:

posts collection schema:

{ _id: String, title: String, body: String, tag_ids: Array}

tags collection schema:

{ _id: String, title: String, post_ids: Array}

So, posts collection will have a tag_ids field of Array type that will contain only ids of the tags it have, same for tags collection will have only array of post_ids.

I’d like to know that’s ok or if there better idea…

Thanks.

PS: The question is not about if I have to use RDBMS or not.

UPDATE 1:

My working app is http://askar-blog.meteor.com

At the moment I can create posts and tags as a separate collections without any relation.

I want to add checkboxes that will list all available tags during post creation like in the Rails app http://postag.herokuapp.com/


This post is being ignored -> Adding checkboxes
#2

What you suggest looks ok.

If a tag is only a unique String, you can also think about this simpler schema:

posts : { _id: String, title: String, body: String }

tags : { title: String, post_id: String }

(the same tag applied to 2 posts will have 2 entries in the tags collection)

It all depends on your needs (i.e. what you need to query).


This post is being ignored -> Adding checkboxes
#3

@Steve: Thanks. Don’t you think your suggestion looks like for one-to-many relations? :wink:

From what you suggested, we know what tag belongs to which post, but we’ll have no idea, in how many posts same tag is used.

Here’s a sample similar app I’ve created in Rails http://postag.herokuapp.com/
I want to make similar in Meteor with http://askar-blog.meteor.com

Sample post:

{
	_id: '1',
	title: '1st post',
	body: 'some text',
	tag_ids: ['1', '2', '3', '4' ]
}

This means there’re 4 tags exist, with their corresponding _id s: 1, 2, 3 and 4.

sample tag:

{
	_id: '1',
	title: 'news',
	post_ids: ['1', '4' ]
}

This will mean that tag news was applied in two posts with _id s 1 and 4.

This is why I thought fields tag_ids and post_ids must be Array type.

Having such schema will allow me to deal with many-to-many relation I thought…


#4

I think with my schema you can have many tags per post and many posts per tag.

Sure we will:

var tagToCheck = "humor";
var tagRecords = tags.find({ title: tagToCheck });
var postIds = tagRecords.map(function(tag) { return tag.post_id; });
var result = postIds.length;

#5

@Steve thanks a lot. I hope I’m getting what you mean.
I will create a new post that’s related to this one.

UPDATE:

Created Defining schemas for 2 models in `many-to-many` relationship


#6

@Steve So, in essence, schema looks like same way as we would deal with one-to-many collections. The difference with many-to-many relation is that you can solve it by a query, am I correct?


#7

You seem to see a many-to-many relationship as a coding pattern, which it is not. A many-to-many relation is a logical concept: it just says that you can have many tags per post and many posts per tag.

From there, there are many ways to implement this logical concept into a physical model. You have suggested one in your first post. I have suggested another one. There are many others. All are fine, but all have specific advantages an drawbacks when it comes to writing and reading documents. For example, if you want to count the number of posts with the same tag, it takes one line of code with your schema and 4 lines of code with mine.


#8

I was just thinking about it. :wink:

Thanks for clarification and your help.


#9

Let’s just stop count lines of code and start thinking in number of queries and iterations in JS etc.


#10

Which approach do you prefer?


#11

I prefer approach which best fit the usecase.

Question is why you need many to many.
I am thinking hard and I cant think of 1 usecase where I would need array of posts mentioned in tag itself.
If I am going to show tag counts in some search, I would have search results on client and I can count them there by query. With pagination in mind, I would still need all unpaginated ID’s of posts matching that search and in that case I can return their tags from posts collection and count them in JS (yes here we could do query on that tag collection if we keep all post_ids there, but would that be really worth it ?)

And I dont like the added cost of every update affecting XY collections and maintaining them consistent.

But if you really have some usecase where you definitely need it, go for that and maintain them this way.
I am not using autoform, so I dont know what possibilities are there to auto-manage that there.

Good luck


#12

Isn’t the relationship between posts and tags called as many-to-many ?


#13

Hey Guys!

When I study SQL and other stuffs correlated, in many cases we describe the M-N relationship simplifying it into a 1-n relationship.

But We are looking to NoSQL data right? The best fit is just having an array inside Post having the tags. You don’t need create a new collection just to creating a relationship with Post and Tags.
You don’t will have a billion tags into a post. And if you need to search the posts in a specific tag you just call something like this:

var tagToCheck = "humor";
var tagCount = posts.find({ tags: {$in: [tagToCheck]}}).count;

And thats it!~


#14

So the sad answer is that Mongo is not good at these queries. You can do them, but they’ll be inefficient and only get worse and worse over time. When your post_ids array has 1000 elements in it, you’re going to see perfromance slow down. The reactive cursors are going to be slow. And you wont be able to $limit those arrays in your publications. The reason is that Mongo is a non-relational database, aka NoSQL. Mongo just isnt meant for this. Its the wrong tool for the job. You’ll want to use a relational database like MySQL, Postgres, or Neo4j if you’re feeling ambitious.

I’m working on ccorcos:any-db (a new version will come out in the coming weeks so dont commit to it yet), which will allow you to use other databases. This is the exact problem I ran into. Mongo isnt a shitty database. Its just not meant for this.


#15

On really Mongo isn’t the best choice if you have many relations. But the case is you need a little much modeling to solve this problem.

If you storing the IDs on the Tags Collection in the future this really will cause the slow performance on your database.

But if you do this choice in the other hand, building the relation in the POST this will scale gracefully because a post never, I said never will be a lot of tags thats cause the performance slow down!

You can do anything you want in Mongo, like you can do anything with anything. But the modeling problem will show the real costs to your software.

On this simple case of Blog’s Posts and Tags or Comments, Mongo modelling correctly solve this problem =D


#16

Thanks. This is what I was wondering: this simple posts-tags case should be doable in Meteor :smile: