I have an application where users can follow other users. I want to have a real-time update system, display the total count of followers a user has.
I've just started playing around with Firebase and Pusher, but I don't understand one thing - will each user have their own 'channel'? How would I handle such thing as a follower counter update?
I followed the tutorial and saw that push method can create lists, so one solution I can see is having a list of all the users, each user being an object something like this:
{ username: 'john_doe', follower_count: 6 }
But I don't understand how would I actually track it on the front end? Should I have a filter, something like this?
var user = users.filter(function(user) { return user.username === 'john_doe'; });
// code to display user.follower_count
Or is there a different way that I'm missing?
Most of Firebase logic is based on listeners, you can add a listener to events happening in your collections and when those events happen, you do something.
One way to go about this would be:
var myFollowerListRef = new Firebase(PATH_TO_YOUR_COLLECTION);
myFollowerListRef.on("value", function(snapshot) {
console.log(snapshot.length);
});
This way, every time your follower collection changes, the asynchronous function fires and you can do what you want with the fresh data.
For more information:
https://www.firebase.com/docs/web/guide/retrieving-data.html
Hope this helps, I'm still a beginner in Firebase.
#Th0rndike's approach is the simplest and works fine for relatively short lists. For longer lists, consider using a transaction. From the Firebase documentation on saving transactional data:
var upvotesRef = new Firebase('https://docs-examples.firebaseio.com/android/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');
upvotesRef.transaction(function (current_value) {
return (current_value || 0) + 1;
});
But I recommend that you read the entire Firebase guide. It contains solutions for a lot of common use-cases.
Related
Ok so I am making a like/dislike system for my website and I got it to work. The only problem is, is that a user can like something more than once, how do I stop this? heres my function
function thumbup(uid, s) {
const prevthumbs = s.thumbs
firebase.db.collection('users').doc(uid).update({
thumbs: prevthumbs + 1
})
}
How can I limit the increment to only one?
To limit how often the user can do something, use their UID as the key for the operation.
For example, if you don't have too many users, you can have a field likedBy in the document which is an array of the UIDs of the users who liked this user.
It's a bit unclear how to exactly implement it in your code for me, as you're already writing to a doc(uid), where usually the user is liking a post or something like that.
I developed an application for the school I work for that create a bridge between our registration system and Google Calendar. In short, it populates multiple calendars (teachers, students, classrooms, and a calendar that contain all courses) based on data from the registration system, it allows teacher to register student attendance and homework for each class and it does a bunch of other stuff.
The application also allows a teacher to trigger an update of the student list when he notices a registered student is not entered as an attendant in the calendar events.
In the code:
I make a call to the registration system to get the updated list of students for the course.
I make a call to Google Calendar to get the recurrences of the events that represent the course in the calendar.
I make a call to Google Calendar to batch patch the "attendees" array of every recurrence
this.updateEvent = function(calendarId, eventId, resource)
{
return $window.gapi.client.calendar.events.patch({
calendarId: calendarId,
eventId: eventId,
resource: resource
});
};
this.batchUpdateEvents = function(calendarId, eventList)
{
var counter = 0;
var batchPromises = [];
for(var i=0; i < eventList.length; i++)
{
if(counter === 0)
{
var batch = $window.gapi.client.newBatch();
}
var event = eventList[i];
batch.add(this.updateEvent(calendarId, event.id, event.resource), {id: event.id});
counter++;
if(counter === 50 || i === eventList.length-1)
{
counter = 0;
batchPromises.push(batch.then());
}
}
return $q.all(batchPromises).then(
function(response){
var updateResults = {};
response.forEach(function(batchResponse){
updateResults = Object.assign(updateResults, batchResponse.result);
});
return updateResults;
});
};
It works fine in most cases but regularly all the calendar events associated with the course are deleted. I can't figure out how to reproduce the bug and since everything is coded in javascript I can't log the errors.
In this process, this is the only 2 times my application interacts with Google Calendar. I really don't see how a get request could delete anything so I assume the batch of patch requests is the problem. Although the only thing I include in the patch is the attendee array so its actually hard to mess it up to that point.
Has anybody got an idea of the direction I should look into? I am a bit at loss here.
It's possible that batchUpdateEvents could be receiving a valid calendarId, but an eventList with blank values. If that's the case checking for a valid value in eventList[0].resource before proceeding to the for loop would prevent blank event values from being saved (which might be causing Google to delete the event). If this script should only add events and never delete them it could also be beneficial to check event.resource before adding it to the batch.
I have seen multipath update example. But before updating any data i have to push it at first place for which i was wondering if there is something called as multipath push?
I want to simultaneously push data under different set of nodes.
eg: Firebase scheme
-Examinations
- pushIdLk12203425
- pushIdML0124245
-RightChoices
- pushIdLk12203425
- pushIdML0124245
-Questions
- pushIdLk12203425
- pushIdML0124245
When i push value under examination node, same values or different values as per my backend architecture have to be pushed under RightChoices and Questions Node. Right now i am doing this using .then callback approach.
I push data under Examinations and then in its .then callback i push in RightChoice and Questions node.
But my concern is what if user closes the app and data just reaches Examinations node and never reaches RightChoices and Questions Node.
I am trying to figure out a better way of having data consistency.
Thanks.
Note: RightChoices and Questions are kept under different nodes for having a better security architecture and i cannot change the schema.
Would be grateful if somebody can help me out. Thanks.
I think you are looking for .update()
Have a look here: https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields:
function writeMultipath(pushID1, pushID2) {
var data = {
id1: pushID1,
id2: pushID2
};
// Write the new data simultaneously to your DB-locations
var updates = {};
updates['/Examinations/'] = data;
updates['/RightChoices/'] = data;
updates['/Questions/'] = data;
return firebase.database().ref().update(updates);
}
I've been trying to do Meteor's leaderboard example, and I'm stuck at the second exercise, resetting the scores. So far, the furthest I've got is this:
// On server startup, create some players if the database is empty.
if (Meteor.isServer) {
Meteor.startup(function () {
if (Players.find().count() === 0) {
var names = ["Ada Lovelace",
"Grace Hopper",
"Marie Curie",
"Carl Friedrich Gauss",
"Nikola Tesla",
"Claude Shannon"];
for (var i = 0; i < names.length; i++)
Players.insert({name: names[i]}, {score: Math.floor(Random.fraction()*10)*5});
}
});
Meteor.methods({
whymanwhy: function(){
Players.update({},{score: Math.floor(Random.fraction()*10)*5});
},
}
)};
And then to use the whymanwhy method I have a section like this in if(Meteor.isClient)
Template.leaderboard.events({
'click input#resetscore': function(){Meteor.call("whymanwhy"); }
});
The problem with this is that {} is supposed to select all the documents in MongoDB collection, but instead it creates a new blank scientist with a random score. Why? {} is supposed to select everything. I tried "_id" : { $exists : true }, but it's a kludge, I think. Plus it behaved the same as {}.
Is there a more elegant way to do this? The meteor webpage says:
Make a button that resets everyone's score to a random number. (There
is already code to do this in the server startup code. Can you factor
some of this code out and have it run on both the client and the
server?)
Well, to run this on the client first, instead of using a method to the server and having the results pushed back to the client, I would need to explicitly specify the _ids of each document in the collection, otherwise I will run into the "Error: Not permitted. Untrusted code may only update documents by ID. [403]". But how can I get that? Or should I just make it easy and use collection.allow()? Or is that the only way?
I think you are missing two things:
you need to pass the option, {multi: true}, to update or it will only ever change one record.
if you only want to change some fields of a document you need to use $set. Otherwise update assumes you are providing the complete new document you want and replaces the original.
So I think the correct function is:
Players.update({},{$set: {score: Math.floor(Random.fraction()*10)*5}}, {multi:true});
The documentation on this is pretty thorough.
Not sure if I'm going about this the right way. I'll map out what I'm trying to achieve and please give me any feedback you can. Also very new to meteor so sorry if I'm a bit uneducated in some aspects. This is going to be a two player game where users login in with accounts-twitter or accounts-facebook. Here's the tricky part it will only initialize the game if there are two users logged in. To figure out who is logged in I have put this line of code in my server portion:
if (Meteor.isServer) {
Meteor.publish("userStatus", function() {
return Meteor.users.find({
"status.online": true
})
});
}
My idea of what needs to be done is write an if statement if(userStatus === true){get a users "_id"} then push that user into an array and have a for loop run through every 2 users signed on in the array and initialize a game for them. Also the main question is how do I grab the users ID if status.online is true? Also any input on how to make this more efficient is much appreciated.
Answering your "main question," you would do this with a mongoDB for-each like so.
Meteor.methods({
getOnline : function(){
var retArr = new Array();
Meteor.users.find({"status.online": true}).forEach(function(u){
retArr.push(u._id); //populated retArr with the id of users online
});
return retArr;
}
});
If I left out something or you need clarification on something, please comment.