Modeling and Publishing "Likes" or "Stars"


#1

So I have some posts that users can “star”. I basically have 2 options here:

  1. Create a collection for posts with a field ‘stars’ that contains an array of userId. This makes sense and its really simple. However, what if, there are thousands of stars? Then this wouldn’t be a good way of doing it. So I’m not going to do it this way.

  2. Create a collection for posts and a separate collection for stars. Thus, I can get the number of stars for a post with Stars.find({postId:postId}).count(). But now the question is how to do publications…

    I want to display each post with the number of stars it has. I could do a meteor method call (or maybe a reactive meteor method) to get the stars for each post, but thats ugly. It seems reasonable to me that I should be able to publish each post with the number of stars for each post as field.

  3. I suppose I could keep a key nStars and an array stars in the collection and just keep them in sync. That wouldn’t be too bad, but keeping things in sync from multiple places seems a hairy to me.

Any suggestions? I’m not a database guy, so any advice would be appreciated.

###EDIT:

I was just thinking this seems like a great place to use Cursor.observeChanges on the server to keep all these numbers in line. The only thing that worries me is that this may cost the server a lot of CPU on startup because it will go through every post on startup…


#2

You may find https://github.com/copleykj/socialize-likeable useful.


#3

Hmm. You’re basically just updating the count every time you add or remove a like:

That’s the only thing I can think of right now. The before and after hooks only run when you call insert on the client though – I like to use Meteor methods, so I’ll just have to do that in the method…


#4

So there seems to be a bigger problem here with using a separate collection. That is how to publish the relationships with a sorted limit?

So perhaps using an array of stars, etc. would be best although not very efficient at scale…


#5

I’ve created a stack overflow question for this:


#6

Is it crazy to consider a SQL database for this? Both MySQL and PostgreSQL are usable reactively in Meteor thanks to @numtel. There’s also an interesting PostgreSQL package with client-side SQL from meteorsteam.


#7

I wouldn’t say its crazy to consider. I’ve been considering Neo4j all day today. Sadly this package seems pretty inadequate – it depends on MongoDb and appears quite inefficient. (Neo4j is really cool though! :wink:

I honestly know very little about the database world and the dev-ops world. Should I use MySQL or PostgreSQL? Or should I use Redis which MDG is working on? How does it scale?

I like meteorstream’s package. It has a nice integration with meteor. numtel’s seem to have some awkward loose ends, and with my lack of experience with SQL, I’d be afraid of getting stuck on something…


#8

Neo4j is brilliant for for this use case. Unfortunately, as you’ve discovered, there’s currently no good integration with Meteor.

For your particular use case SQL would probably do a good job (almost certainly more easily than with MongoDB), but there are enough performance tuning optimisations, that unless you are familiar with (or know someone familiar with) SQL, then you may struggle.

As for MySQL vs PostgreSQL - that’s not a decision I would like to make for you. From my experience there are pros and cons to both.

Redis is awesome for data which needs to be accessed frequently or which is transient. However, it is not the best choice for anything involving complex data queries, since these need to be moved out into code, save for a few really nice set operations. The restrictions around Lua in Redis means that wouldn’t help, either.

However, before abandoning MongoDB altogether, I wonder whether something could be done using the aggregation pipeline? I played with that some months ago and it was pretty quick, but I don’t know enough about it to be confident in its use for what you’re trying to do.


#9

The aggregation pipeline is interesting but there’s still no concept of a “foreign key”. The entire pipeline acts only over one collection… The aggregation pipeline also isn’t reactive…

I checked out the implementations for SQL and they have their issues as well. MySQL doesnt have latency compensation – you have to do that manually. And PostgreSQL doesnt have any security or subscriptions…

I have an idea for how to do a more simple database driver which I just elaborated on in this issue ticket…

https://github.com/meteor-stream/meteor-postgres/issues/244

It appears, though, that Meteor is not a great choice for this kind of app though… I’m curious how other platforms deal with reactive queries?

Also, have you heard of RethinkDB? They seem to have pub/sub built in (like redis) and they have joins…


#10

True enough, but of all the things you might have to address, latency compensation is probably the easiest.

If a user’s feed is dependent on other users starring posts, then from the point of view of that user the subscription requirements are:

(1) Your followed users star/unstar posts.
(2) You follow new users.
(3) You un-follow users.

In all cases the publication needs to update reactively, but only in case (3) is there a potential for latency compensation - and you can only realistically use it if you know that removing a followed user affects your feed - and which posts within that feed.

I have had experience of the numtel:mysql package and the speed of reactivity is impressive: Most impressive features of Meteor to show in demos

Yes - heard of it and seen a lot of interest from within the Meteor community. Also, @slava has been working on a full-stack Meteor implementation, which looks promising. However, I have no personal experience in it.