Top-50 click&time scored posts - meteor

We all know microscope from discovery meteor. The app is fine, it operates only with the number of upvotes. In the Best page it sorts posts by upvotes in descending order, upvote number is stored for each post and gets updated each time some user upvotes a post.
Imagine now we want to implement something like hacker news have - not only a click-based rating, but also a time-based rating. Lets now define that I will use word 'click' to describe an user action of clicking on post in the post list. This 'click' increases total number of clicks of this post by 1.
For thouse who do not knowe how hacker news algorithm work I will briefly explain. In common the total number of clicks of certain link (post) is divided by:
(T+2)^g
where T - total number of hours passed since post publishing time and now, and g is a "sensitivity" thing, lets call it that, which is just a number, 1.6, or 1.8, doesn't matter. This decrease influence of clicks as the time goes by. You can read more info (http://amix.dk/blog/post/19574)[here], for example.
Now, we want to have top-50 click&time-rated posts, so we need to query mongo to find all posts, sorted by score, calculated with formula from above.
I can see two major approaches to do so, and I find all of them quite bad.
First one, (the way I do now) subscribe to all posts, in template hepler prepare data for rendering by
rankedPosts: function() {
rawPosts = posts.find().map( function(item) { item.score = clicks/(T+2)^g; } ); // to add score for each post
rawPosts = _.sortBy( rawPosts, function(item) { return item.score*(-1); }) // to sort them by calculated score
rawPosts = _.first( rawPosts, 50 ); // to get only first 50
}
and then use rankedPosts for rendering. The bottleneck here is that each time I have to run through all posts.
Second one - somehow (I do not know how, or if it even possible) to subscribe for already scored/sorted/filtered collection, assuming meteor/mongodb can apply their magic to score/sort/filter (and recalculate score each new hour or new click) for me.
Now, obvious question, what will you recommend?
Thanks in advance.

Think about numbers. In a working page, you can have thousands of mosts, millions if the page is successful. Fetching all of them just to find the top 50 doesn't make sense.
I'd recommend storing the final calculated rating in a field. Then in subscription you apply sort by that field and desired limit. When post gain a new click, you simply recalculate the value and save it to db. Finally, in a cron job or meteor interval you update the rating of all items in the database.

Related

How can i avoid the duplicate Field counter from two user at the same time pressing the bottom

i have collection which contains the whole users products , and to avoid the casts of reading all docs to get the length of the collection , i increase one value +1 to every field once it's doc being created , ok now everything is ok
here i am using this method to chick if doc if exist or not so i can avoid the duplicate of counter in case offline mode
removeProduct1(){
FirebaseFirestore.instance.collection("product").doc('product1')
.get(const GetOptions(source: Source.server)).then((value1) {
if(value1.exists) {
FirebaseFirestore.instance.collection("product").doc('product1').delete();
FirebaseFirestore.instance.collection("product").doc('productCount').update({
'productCount': FieldValue.increment(-1),
});
}
}).onError((error, stackTrace) {
ScaffoldMessenger.of(context).showSnackBar(snackBar,);
});
}
also everything is ok , but i noticed if two user pressed the button for this method at the same time so its gonna be two value decrease -2
maybe someone will think its rarely when two user hit the button at the same time , well this is only simple sample of what i have for real instead , i have page which contains too many users which is not be rarely for being two user hit the button
EDIT FOR MOER EXPLATION
i have collection called Friends which contains User IDs of friends together
for example user1 his id is ABC and user2 his id is DEF
so id becomes final into the Friends collection like this ABCDEF by following function
and also this following function increase counter +1 for ever one of them
makeFriends(){
// here i make sure first if the friends Ids are not exists To avoid suspiciously increasing the counter in offline mode and its work very well
FirebaseFirestore.instance.collection("Friends").doc(user1Id+user2Id).get().then((value) {
if(!value.exists){
// here to add ids to the friends collection
FirebaseFirestore.instance.collection("Friends").doc(user1Id+user2Id).set({
'test':''
});
//here to increase counter in other colection which is users for both user
//user1
FirebaseFirestore.instance.collection("users").doc(user1Id).update({
'friendsCounter':FieldValue.increment(1)
});
//user2
FirebaseFirestore.instance.collection("users").doc(user2Id).update({
'friendsCounter':FieldValue.increment(1)
});
}
});
}
Okay now everything going fine and they became a friends with one value increased and their Ids became unit into Friends collection .. and here image for better explanation
image 1
image
here i have function responsible for deleting friend with decrease one value from FriendsCount Field for both of them
deleteFriends(){
// here i make sure first if the friends Ids are exists To
// avoid suspiciously decrease the counter in offline mode and its work very well
FirebaseFirestore.instance.collection("Friends").doc(user1Id+user2Id).get().then((value) {
if(value.exists){
// here to remove ids from the friends collection
FirebaseFirestore.instance.collection("Friends").doc(user1Id+user2Id).delete();
//here to decrease counter for both user
//user1
FirebaseFirestore.instance.collection("users").doc(user1Id).update({
'friendsCounter':FieldValue.increment(-1)
});
//user2
FirebaseFirestore.instance.collection("users").doc(user2Id).update({
'friendsCounter':FieldValue.increment(-1)
});
}
});
}
ok now also everything going fine .. lets say user1 deleted his friend user 2 , by the previous functionthe Friends id which is ABCDEFhas been deleted so next time if user 2 want to do the same opretion it will fail because Friends ids are not exist anymore ..
the problem IS :
lets say these two users are still friends and
these two user visited each others profiles and hit the button at the same time which is call the pervious function (deleteFriend) so they gonna get the same return value which is (yes exists) then will be double decrease value for both of them instead of one as required .
means if their friendsCount was 1 both of them when they was a friend so tee value will be -1 instead 0 because there two operation was proceed
and this happen only if these two user hit the button at the same moment , but if the user 1 hit the button before user 2 then user 2 want to do same operation so he ganna fail because friendId was deleted by user1 operation as a condition statement in previous function ..
if(value.exists) i thought it too fast to delete friendIds before it give same result to other user if they together call the function at the same time
of course i can prevent the button of calling the delete function in case one of these user is already deleted other but I didn't see this as a strong solution since i can't grantee traffic jam or any reason else like bad users behavior .. etc , also basically i can't do it because delete button must be available as long as they still a friends
Note: this also happen in addFriends buttom call too if two users hit it at the same time , double value +2 instead one ..
i need any way to avoid server to give same result if there was two user query same doc at the same time , or any good solution
If you need to both read and write a document to update it, you should use a transaction to prevent the race condition that you now have when multiple users perform the operation around the same time.
Here you definitely want to use a transaction, because if the delete fails for whatever reason, the decrement operation should also fail (and vice versa).
The FlutterFire documentation on transactions also has a good explanation and example code to get started.

Wordpress: Counter for page views to be inserted in a different page

I have been looking for a plugin in wordpress that allows me to insert a page view counter in a different page: I´ll explain;
In page A I have buttom with a contact form to vote a video (it is a video contest). This contact form sends the voter an email with a link to page B so that they can validate their email this way. Every visit to page B will be counted as a vote.
The thing is that I want to count the number times that page B is accessed to show it in page A (to show the number of votes next to the video).
It seems pretty straightforward but I can´t find an easy way to do this. Do you think you could help me?
Thanks!
Guzmán
If a very small number of people will access the page you can just store a value in WordPress and add to it each time. If you expect a lot of users on the page at once you may need a more complex method.
For a lightly trafficed page, with the risk that some visits might not be counted you could leverage the post meta and simply store a counter variable. If two people viewed the page at the same time they could get the same value for the counter variable and so they would not properly increment the variable.
You could add this to the template for the page in question:
$vcount = get_post_meta($post->ID, "view_counter");
add_post_meta($post->ID, "view_counter", $vcount+1, true);
So two people accessing the page would end up with equal $vcount variables. To display the count you'd just need the post id for the post you saved the meta to: print get_post_meta(<POSTIDHERE>, "view_counter", true);
If you need to have a more robust solution, you'd want to store a unique value for each visitor and then to report the total you would count the values and display it. So you could store the visitor's IP address as a multi-value meta:
add_post_meta($post->ID, "view_counter", $_SERVER['REMOTE_ADDR'], false);
Then to display the count you'd need to count the number of post meta values stored with the view_counter key:
$ips = get_post_meta(<POSTIDHERE>, "view_counter", false);
$views = count($ips);
print "Total views: $views";
This is just a sample solution, you should probably check to see if an IP already exists and consider throttling individual IPs. You could also risk filling your database if you have a small shared server unless you write some additional code to keep this from being abused since it adds data to your database on every page view. Finally this will not work correctly if you have any type of caching enabled.
Depending on the plugin that you are using for your contact form you may also be able to report the number of times that the contact form was submitted by querying the database directly.
For more information see the documentation for add_post_meta and get_post_meta
(disclaimer, code written from memory and documentation, not tested)

Pagination in application which use firebase.com as database

Front end application will use firebase.com as database.
Application should work like blog:
Admin add / remove posts.
There are "home" page which show several articles per page with "Next" and "Prev" buttons and page which show single article.
Also I need deep linking.
I.e. when user enter URL http://mysite.com/page/2/ I need that application show last articles from 10 to 20, when user enter URL http://mysite.com/page/20/ application show last articles from 200 to 210. Usual pagination.
Main question - is it possible to achieve this if use firebase.com.
I read docs at firebase.com, I read posts here. "offset()" and "count()" will be in the future, use priority, in order to know count of items and not load all of them use additional counter.
Based on this I suppose this:
ADD POST action:
get value of posts counter
set priority for new post data equals to value of posts counter
increase value of posts counter
DELETE POST action
get value of priority for post data
query posts data which have value of priority more than priority for post data which will be deleted and decrease their value
decrease value for posts counter
GET POSTS FROM x TO y
postsRef.startAt(null, x).endAt(null, y).on(... and so on)
Thing which I not like in this way are actions for DELETE POST. Because index of posts will be from 0 to infinity and post with less priority is considered as post which was created earlier so if I have 100000000 posts and if I need to delete 1st post then I need to load data for 99999999 next posts and update their priority (index).
Is there any another way?
Thanks in advance, Konstantin
As you mentioned, offset() will be coming, which makes your job easier.
In the meantime, rather than using startAt and endAt in combination, you could use startAt and limit in combination to ensure you always get N results. That way, deleted items will be skipped. You then need to check the last id of each page before moving to the next to find the proper id to start on.

filtering datagrids

In a simple scenario there is a webpage with a datagrid containing 2 columns; first name and country. There's a filter set on the grid to filter out all Australians. There's a form on the same page to add new records and a user decides to add someone from Australia. This record does not meet the filter criteria so would not normally display. However, this might be confusing from the users perspective as they might not have confidence that the person has been successfully added or have forgotten that the filter will mean the new entry is not displayed.
What is the best way to handle this from a usability perspective?:
display the new entry but leave the list in a state inconsistent
with the filter criteria?
filter out the new entry but risk confusing the user?
provide feedback to the user that the record was successfully
added but may be filtered out of the list?
?
Three tools I use, Mingle, Jira, and Quicken, use this implementation very effectively; a slight modification to your number 3:
Provide feedback to the user that the record was successfully added, but won't be shown, and provide a link to the record using its record identifier (record number + title).

Function for Google Feeds API to skip entries?

Is there a way to call the Google Feed API so that it skips X number of entries in a feed?
To explain the context:
I'd like to load additional entries on demand from a particular feed. So a user can click a "Load more" type button, and an ajax function fires to retrieve additional entries. Just to put some numbers on the scenario, lets say I load 10 entries by default, and want to load an additional 10 each time a user clicks on a "load more" button.
With the historical entries / numEntries API functions, I can essentially solve my problem by retrieving 10 + ( number of entries already loaded ), and only output the last 10. But this is pretty ugly, because every time a user loads another 10 entries, they have to load ALL the previous entries as well, so the load gets larger everytime they load more entries. Seems pretty inefficient!
Inspecting the API docs at Google, I couldn't find any reference to a "skip entries", or "start from X entry" type of API method / variable, so I could make my ajax call nice and lean, and just get 10 entries, starting from ( number of entries already loaded).
Anybody have any experience / suggestions for me?
I think you'll have to load all items first, but only display 10 at first. If they click "show more" you then show them the next 10 (you'll have to keep an internal pointer of your position in the list of items). So essentially, you aren't "loading" 10 more, you're "showing" 10 more.

Resources