Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB dynamic ranking

I use MongoDB and have a collection with about 100000 entries.

The entries contain data like that:

{"page": "page1", "user_count": 1400}
{"page": "page2", "user_count": 1100}
{"page": "page3", "user_count": 900}
...

I want to output a ranking of the entries according to the user_count like:

#1 - page1
#2 - page2
#3 - page3
...

...so far so good. I can simply use a loop counter if I just output a sorted list.

But I also have to support various search queries. So for example I get 20 results and want to show on which rank the results are. Like:

#432 - page1232
#32  - page223
#345 - page332
...

What's the best way to do that? I don't really want to store the ranking in the collection since the collection constantly changes. I tried to solve it with a lookup dictionary I have built on the fly but it was really slow. Does MongoDB have any special functionality for such cases that could help?

like image 918
horace Avatar asked Oct 03 '22 10:10

horace


2 Answers

There's no single command that you can use to do this, but you can do it with count:

var doc = db.pages.findOne(); // Or however you get your document
var n = db.pages.find({user_count : {$gt : doc.user_count}}).count(); // This is the number of documents with a higher user_count
var ranking = n+1; // Your doc is next in a ranking

A separate qustion is whether you should do this. Consider the following:

  • You'll need an index on user_count. You may already have this.
  • You'll need to perform a count query for each record you are displaying. There's no way to batch these up.

Given this, you may impact your performance more than if you stored the ranking in the collection depending on the CRUD profile of your application - it's up to your to decide what is the best option.

like image 135
Charles A Avatar answered Oct 12 '22 11:10

Charles A


There's no simple approach to solve this problem with MongoDB. If it is possible I would advise you to look at the Redis with its Sorted Sets. As documentation says:

With Sorted Sets you can: Take a leader board in a massive online game, where every time a new score is submitted you update it using ZADD. You can easily take the top users using ZRANGE, you can also, given an user name, return its rank in the listing using ZRANK. Using ZRANK and ZRANGE together you can show users with a score similar to a given user. All very quickly.

You can easily take ranks for random pages by using MULTI/EXEC block. So it's the best approach for your task I think, and it will much faster than using MapReduce or reranking with mongodb.

like image 31
evilive Avatar answered Oct 12 '22 11:10

evilive