Linking Data in Firebase - angularjs

I am designing a forum and have a layout like this in on my Firebase:
root
|-posts
|-postID1
|-creator: "userOne"
|-creatorUID: "simplelogin:1"
|-text: "Some Text"
|-postID2
|-creator: "userTwo"
|-creatorUID: "simplelogin:2"
|-text: "Some Other Text"
|-profile
|-simplelogin:1
|-firstName: "John"
|-user: "userOne"
|-simplelogin:2
|-firstName: "Sue"
|-user: "userTwo"
On my forum page. I simply use a Angular ng-repeat to get all of the posts on Firebase and list them out. I also want to print out the first name of whoever created the post, but right now, I can only access {{ post.creator }}, which just gives the username of the person who posted. How can I link the post's creator (or creatorUID) with the first name field of that person's profile?

If you're just displaying the the users firstName I would place the users name in the postIDX object.
This would be quicker and produce less requests to Firebase with you going back and fourth with each post to get the usersFirst name.
more information on structuring data and best practices can be found here: https://www.firebase.com/docs/web/guide/structuring-data.html
Updated from response
if you wanted to get the user details then within every request to the postIDx you'd need to do something similar to this (not tested and quick mock up).
var fbRef = new Firebase('firebase path'),
postDetailsObject = {};
fbRef.child('posts').once('value', function(snapshot) {
// loop through each post
snapshot.forEach(function(childSnapshot){
var postDetails = childSnapshot.val(),
profileDetails;
postDetailsObject.post = postDetails;
fbRef.child('profile/' + postDetails.creatorUID).once('value', function(profileData) {
postDetailsObject.profile = profileData;
});
})
});
Then return the postDetailsObject in to angular so you can loop through the single object.

Related

Getting All Users Uid from Firebase / Flutter/Dart

My application is kind of a poll application. So the admin asks a question, and users respond to that question, and every data is stored in Firestore. In the admin page, the admin can see the question that he/she created, and when the admin clicks the question, he/she can see the answers of users to this question.
On the answers page, I am trying to reach every user's uid but I couldn't achieve this. I can print them but I can't use them in a way. I think I make some mistakes with Firebase functions.
This is an example of a method that I am trying to return the list includes of the specific question. But this function doesn't return anything.
List getUserIDData() {
List<String> growableList = [];
List<String> userAnswerList = [];
String adminQuestion = "What is the reason of life?";
Firestore.instance.collection("user").getDocuments().then((snapshot) {
snapshot.documents.forEach((element) {
growableList.add(element.documentID);
});
for (int i = 0; i < growableList.length; i++) {
Firestore.instance
.collection("user")
.document(growableList[i])
.collection("answers")
.where("adminQuestion", isEqualTo: adminQuestion)
.getDocuments()
.then((snapshot) {
snapshot.documents.forEach((element) {
userAnswerList.add(element["userAnswer"]);
});
});
print(i);
}
});
return growableList;
}
I also tried something with StreamBuilder, but still, after Firestore.instance, everything is deleted automatically. In Firestore, everything looks good, but after it finished growableList doesn't stay the same and this function returns null.
Do you have any suggestions to do so?
From what I can see you are using a very old version of FlutterFire, for example the following has been changed:
BREAKING: getDocuments/get has been updated to accept an instance of GetOptions (see below).
DEPRECATED: documents has been deprecated in favor of docs.
DEPRECATED: documentID has been deprecated in favor of id.
You might want to migrate to a newer version.
With snapshot.documents you get a List<QueryDocumentSnapshot<T>> according to the documentation. So I looked at the QueryDocumentSnapshot and was surprised that you apply element["userAnswer"] directly to it. According to the documentation you have to use element.data() to get the data.
If that doesn't help I would need more information in the form of output what's behind the element variables.

Any performance concern when using $firebaseArray to add a new record to Firebase?

I got the following AngularJS sample code from the document regarding how to add a new record to Firebase. It works fine and the new record can be created successfully.
While I also noticed that from the callback we can get all the siblings with the list variable, which is interesting.
My question is that would there be any performance latency when the list is large, say 100,000 records. Can anyone shed light on this?
var list = $firebaseArray(ref);
list.$add({ foo: "bar" }).then(function(ref) {
var id = ref.key();
console.log("added record with id " + id);
list.$indexFor(id); // returns location in the array
});
$firebaseArray synchronizes a collection from the Firebase Database to your client, for easy display in your Angular views. You should never synchronize more data than the user needs to see, and 100,000 records seems very much beyond what a user should ever see.
If you just want to add a new item, you're better off using the Firebase JavaScript SDK directly:
ref.push({ foo: "bar" }).then(function(ref) {
var id = ref.key();
console.log("added record with id " + id);
});
Since AngularFire is built on top of the Firebase JavaScript SDK, it will pick up this change automatically.

firebase database child reference issue

I am trying to create a meeting firebase reference inside my parent users
I am implementing this line:
var meetingRef= firebase.database().ref('users/' + $rootScope.currentUser.$id + '/meetings');
Under my users, I have registered user Id's as hashes, which I make use of in the above code. As the current user gets authenticated, he gets to create some meetings from the UI. I want these meetings to go into his particular hash in the firebase database.
But every time I create a meeting, some undefined child reference of users gets created under which I see the meetings of authenticated users.
This is my complete code-
myApp.controller("MeetingsController",
['$scope','$rootScope','$firebaseArray',
function($scope,$rootScope,$firebaseArray){
var ref = firebase.database().ref();
var auth = firebase.auth();
auth.onAuthStateChanged(function(user) {
if (user) {
var meetingRef= firebase.database().ref('users/' + $rootScope.currentUser.$id + '/meetings');
var meetingsInfo=$firebaseArray(data);
$scope.addmeeting=function(){
meetingsInfo.$add({
name:$scope.meetingname,
date:firebase.database.ServerValue.TIMESTAMP
}).then(function(){
$scope.meetingname=' ';
})
};
}
});
}]);
If you are wondering as to where that $rootScope.users.$id value is coming. It comes from a service that I created and the $id is the value that the current authenticated user's hash is.
I want the meetings to go inside authenticated users hash. I think I am creating wrong reference path. How can I achieve this one?
Images attached:
Current:
Required:
Aakash,
Your code to create the meetings folder and the drawing you added to the post do not go together. Currently, you are using this:
var data = firebase.database().ref('users/' + $rootScope.currentUser.$id + '/meetings');
But if you really want meetings to be a direct child of users the way you have drawn then you will need to get rid of the user id piece of the reference like this:
var data = firebase.database().ref('users/meetings');
This is based off what you added to your post, however, something tells me that you didn't mean to draw meetings in there as a direct child to users. If that's what you really wanted, then that would be your answer.
This next piece is a guess, but is the following structure what you are trying to create?
Because if it is, you need something different which I can also help with, just let me know.
Update:
Ok, based on your comment, I see that you are going for the data structure in my picture.
It looks like your code is ok, however, at the exact moment that the data variable is being set, your $rootScope.currentUser.$id is undefined. This is possibly due to the asynchronous nature of javascript. This means that sometimes your user variable is true, however, your $rootScope.currentUser.$id is still not quite caught up and is undefined.
I would run a check on the variable before continuing, just to make sure everything is in order:
if($rootScope.currentUser.$id != undefined){
var data = firebase.database().ref('users/' + $rootScope.currentUser.$id + '/meetings');
}else{
return;
}
This will stop you from ever getting a new undefined object in your database.
I have found an answer to this one.
I changed the meetingRef to:
var meetingRef = firebase.database().ref('users/' + user.uid + '/meetings');
and it worked for me.

How to add to a list in Firebase without overwriting

I am trying to create a 'Favorites' section in my app where you hit a button and it is added to a user favorites list in firebase. I am using the ionic platform.
I created a factory to handle the favourites as they come in. and i use the getAuth() function to get the unique userID so i can just pull it when the user logs on. This is my attempt but i am not getting the result i wanted which is simply something like :
< userid >:
{
0: "fav1"
1: "fav2"
}
.factory('Favourites',function($firebaseArray){
var ref = new Firebase("https://experiencett.firebaseio.com/");
var authData = ref.getAuth();
var favs = $firebaseArray(new Firebase('https://experiencett.firebaseio.com/favourites/'+authData.uid+''));
return {
all: function() {
return favs;
},
add: function(){
var up=new Firebase('https://experiencett.firebaseio.com/favourites/');
var usersref=up.child(authData.uid);
usersref.push({3:"paria"});
},
When you call push() you are generating a unique id. While that is great for many use-cases, it is not good here since you want to control the path that is written.
Since you're already constructing the path with child(authData.uid) you can simply update it with update():
usersref.child(authData.uid).update({3: "paria"});
This will either update the existing value at 3 or write the new value for 3, leaving all other keys under /users/<uid> unmodified.
Alternatively if you want to replace the data that already exists at users/<users>, you can use set() instead of update().
This is all covered in the Firebase JavaScript SDK in the section on storing user data. It is not covered in the AngularFire documentation, since there is nothing specific to Angular about it.

Issues with single-requests in Restangular

I'm having a slight issue with my ability to consume REST data retrieved via Restangular in an angular controller. I have the following code which works fine for a list of accounts:
var baseAccounts = Restangular.all('accounts');
baseAccounts.getList().then(function(accounts) {
$scope.accounts = accounts;
});
This works perfectly for a list. I use similar syntax for a single account:
var baseAccount = Restangular.one('accounts');
baseAccount.getList(GUID).then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
I am using ng-repeat as the handling directive for my first request. I am attempting to bind with {{ account.name }} tags for the single request, but it does not seem to display any data despite the request being made properly. GUID is the parameter I must pass in to retrieve the relevant record.
I have combed through Restangular docs and it seems to me like I am composing my request properly. Any insight would be greatly appreciated.
EDIT: I've tried all of the solutions listed here to no avail. It would seem Restangular is submitting the correctly structured request, but when it returns it through my controller it shows up as just a request for a list of accounts. When the response is logged, it shows the same response as would be expected for a list of accounts. I do not believe this is a scoping issue as I have encapsulated my request in a way that should work to mitigate that. So, there seems to be a disconnect between Request -> Restangular object/promise that populates the request -> data-binding to the request. Restangular alternates between returning the array of accounts or undefined.
Have you looked at:
https://github.com/mgonto/restangular#using-values-directly-in-templates
Since Angular 1.2, Promise unwrapping in templates has been disabled by default and will be deprecated soon.
Try:
$scope.accounts = baseAccounts.getList().$object;
try:
var baseAccount = Restangular.one('accounts', GUID);
baseAccount.get().then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
The problem here is that it's expecting an array to be returned. I'm assuming that you are expecting an account object. Thus we need to use the get function, intead of getList()
The one() function has a second argument that accepts an id e.g. .one('users', 1). You can take a use of it.
CODE
var baseAccount = Restangular.one('accounts', 1); //1 would be account id
baseAccount.getList('account').then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
OR
var baseAccount = Restangular.one('accounts', 1); //1 would be account id
baseAccount.all('account').getList().then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
For more info take look at github issue
Hope this could help you, Thanks.

Resources