I am trying to retrieve the user's key based on the child's email, which is student#memail.com in this case. I have tried many ways but could not get a way to retrieve the key of the record. I want to retrieve the value KKTxEMxrAYVSdtr0K1NH , below is the snapshot of the database
Currently, if((childSnap.val().role) == "student") { returns me student and snap.key() returns me "User". How do I retrieve KTxEMxrAYVSdtr0K1NH ?
What method are you using to retrieve the node? If you are using on "child_added" then you can use: childSnap.key
If you are using on "value" then your references is the keys in the response object. So you can use:
for (var key in childSnap.val()) {
console.log(key)
}
or
childSnap.forEach(...)
Here is an example to clearify (check the console):
https://jsfiddle.net/qrLvbok4/1/
There is a difference between value and child_added, check the list for child events section: https://firebase.google.com/docs/database/web/lists-of-data
var ref = firebase.database().ref('Users');
ref.on('child_added', function(snap) {
// You can retrieve the parent key by calling snap.key
console.log(snap.key);
});
UPDATE (Get parent key by email):
var ref = firebase.database().ref('Users').orderByChild('email').startAt('student#memail.com').endAt('student#memail.com');
ref.once('value', function(snap) {
console.log(Object.keys(snap.val())[0]);
});
Related
I'm using angular-ui-fullcalendar to show and edit events. Users can log in and have unique uid when logged in. I want to use this to distinguish events made by current user from other events. I want to give current user events another backgroundColor.
What is the best way to do this??
I tried several things. My data looks like this:
```
database
bookings
-KWnAYjnYEAeErpvGg0-
end: "2016-11-16T12:00:00"
start: "2016-11-16T10:00:00"
stick: true
title: "Brugernavn Her"
uid: "1f17fc37-2a28-4c24-8526-3882f59849e9"
```
I tried to filter all data with current user uid like this
var ref = firebase.database().ref().child("bookings");
var query = ref.orderByChild("uid").equalTo(currentAuth.uid);
var bookings = $firebaseArray(query);
$scope.eventSources = [bookings];
This doesn't return anything. If I omit the filter in line 2 it returns all bookings as expected. But even if the filter worked it would not solve my problem, because I want to fetch both current user events and all other events. Firebase does not have a "not equal to" filter option...
I tried to loop through each record and compare uids and setting backgroundColor if condition was met:
var ref = firebase.database().ref().child("bookings");
var bookings = $firebaseArray(ref);
bookings.$ref().on("value", function(snapshot) {
var list = snapshot.val();
for (var obj in list) {
if ( !list.hasOwnProperty(obj) ) continue;
var b = list[obj];
if (b.uid === currentAuth.uid) {
b.className = "myBooking";
b.backgroundColor = "red";
}
}
});
$scope.eventSources = [bookings];
But this causes asynchronous problems so the 'bookings' array assigned to $scope.eventSources wasn't modified. I tried to move the $scope.eventSources = [bookings] inside the async code block but FullCalendar apparently can't handle that and renders nothing.
I also tried this but no luck either:
bookings.$loaded()
.then(function(data) {
$scope.eventSources = [data];
})
.catch(function(error) {
console.log("Error:", error);
});
What is the best solution to my problem?
If you're looking to modify the data that is loaded/synchronized from Firebase, you should extend the $firebaseArray service. Doing this through $loaded() is wrong, since that will only trigger for initial data.
See the AngularFire documentation on Extending $firebaseArray and Kato's answer on Joining data between paths based on id using AngularFire for examples.
I'm new to Firebase but I need to update a prop 60 seconds after it is pushed to Firebase. How can get the dynamic key Firebase creates after a .push() is successful?
function storeData(val){
$scope.ref = new Firebase('...')
$scope.ref.push({'va1': val, 'status': 'active' });
//after push give me back the newly created key string for that item only
}
Pass the key property at the end of push().
function storeData(val){
const dataRef = new Firebase('...')
const key = dataRef.push({'va1': val, 'status': 'active' }).key;
}
// Before returning the key value, it pushes the data to the database.
I figured it out. I found this worked like a charm
$scope.ref.limitToLast(1).on("child_added", function(snapshot) {
console.log(snapshot.key());
})
I'm trying to search for an object by a property with this code :
ref.orderByChild("aFieldNameOnTheFirebaseCollection").equalTo(mySearchArgument).limitToFirst(1).on("child_added", function(snapshot) {
console.log("Yes the object with the key exists !");
var thisVerificationVarisSetToTrueIndicatingThatTheObjectExists = true ;
});
This works ok if the one or more objects are found on the collection. But, I need to know if no objects exists. I could set the verification var to false before the verification but the verification process is async and I need wait until it is finished. Shoul I use a promise ?
A child_added event will fire if (and only if) a child is added. So you cannot use it to detect whether a matching child exists.
Use a value event for that:
var query = ref.orderByChild("aFieldNameOnTheFirebaseCollection").equalTo(mySearchArgument).limitToFirst(1);
query.on("value", function(snapshot) {
if (snapshot.hasChildren()) {
console.log("Yes the object with the key exists !");
var thisVerificationVarisSetToTrueIndicatingThatTheObjectExists = true ;
}
})
I have a small app that users can use to search for a movie, and then add it to their watchlist. Currently it is possible to add 1 movie multple times for the same user. Which ofcourse isn't expected behaviour.
My solution would be to find the unique id of the movie that's being added and crosscheck that with my movies_users data. If the movie_id value exists, do this, else do this.
At the moment I do have the unique movie id of the movie that's being added,
$scope.movieListID = response;
console.log ($scope.movieListID.id)
Which gets ouputted like a string, like so,
314365
And I got the movie records from the current user,
$scope.moviesCheck = response.data;
console.log ($scope.moviesCheck)
Which looks like this,
[{"id":2,"title":"Black Panther", "movie_id":"284054"}]
So what would be a good way to check if the result from $scope.movieListID.id already exists in the $scope.moviesCheck data?
* update *
Trying a suggestion below does not give the expected result.
var exists = function (id) {
$scope.moviesCheck.forEach(function (movie) {
console.log (movie.movie_id)
console.log (id)
if (movie.movie_id === id)
console.log ('duplicate')
else
console.log ('not duplicate')
});
}
exists($scope.movieListID.id);
The console.log output from this is,
312221
312221
not duplicate
Which clearly are duplicate results.
You can add a function in your controller to check if the movie exists in the list
var exists = function (id) {
$scope.moviesCheck.forEach(function (movie) {
if (movie.id === id)
return true;
});
return false;
}
// and call it
exists($scope.movieListID.id); // true or false
I'm not 100% if this is a good way to do this, but for me it works and I think it's pretty low on performance,
movieService.loadMovies().then(function(response) {
$scope.moviesCheck = response.data;
var arr = $scope.moviesCheck
function myIndexOf(o) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].movie_id == o.exisitingMovie_id) {
return i;
}
}
return -1;
}
var checkDuplicate = (myIndexOf({exisitingMovie_id:movie.id}));
if (checkDuplicate == -1) {
From your question I've understood that, based on the object exists using id in the array of object, you have to do different action.
You can use $filter for this. Inject the filter for your controller and assign it to the scope. So this will be available whenever you want in this controller.
$scope.cFilter('filter')($scope.movies, {movie_id:$scope.existingMovie.movie_id}, true);
$sope.movies - is the list of movies passed to the filter. You can
send any list based on your need.
{movie_id:$scope.existingMovie.movie_id} - This one is the object
which one we need to find. This can be based on your need. Since we
are searching movie_id, we need to send the object with property
and value. {movie_id:$scope.existingMovie.movie_id}, Here movie_id is
the property and followed by the value with the colon.
true: This indicates that, to search exact matched values. By default
this is false. If this is set to false, then if we want to search 54
in the movie id, this will returns the objects whichever contains 54
as part of the value.
app.controller('controller', ['$filter',function($filter){
$scope.cFilter= $filter;
$scope.Exists=function(){
$scope.movies=[{"id":2,"title":"Black Panther", "movie_id":"284054"},{"id":3,"title":"Black Panther", "movie_id":"32343"},{"id":4,"title":"Black Panther", "movie_id":"98863"}]
$scope.existingMovie={"id":3,"title":"Black Panther", "movie_id":"32343"};
var _obj=$scope.cFilter('filter')($scope.movies, {movie_id:$scope.existingMovie.movie_id}, true);
if(_obj && _obj[0])
{
Console.log('object exists')
}
else
{
Console.log('Object is not found')
}
}
}])
Many Thanks Jeeva Jsb. This got me on the right track, however I thought I would clarify with a practical example that seems to work as expected.
So I have a function called getData which get the AJAX array but we need to check if the record exist before added to scope (else we get duplicates)
if (d.data.length) {
for (var i = 0; i < d.data.length; i++) {
var doesExist = $filter('filter')($scope.notifications, {NotifId:d.data[i].NotifId}, true);
if (doesExist.length == 0){
$scope.notifications.push(d.data[i]);
}
}
}
This should look familier...
when we are iterating through the returned AJAX object we need to check the ID of the (in my case notificiation)
var doesExist = $filter('filter')($scope.notifications, {NotifId:d.data[i].NotifId}, true);
This line creates a new array by filtering the existing array in scope ($scope.notifications) and passing in the same value from you interation.
If the value exists the object will be copied to the new array called doesExist.
A simple check of length will determine if the record needs to be written.
I hope this helps someone.
I want to know how to loop through the children of everyone. I'm using Firebase and AngularJS.
My firebase object looks like:
To me it looks like a dictionary, so from Getting a list of associative array keys I have tried
syncData('everyone').$bind($scope, 'everyone').then(function() {
var keys = $scope.everyone.$getIndex();
for (var key in $scope.everyone) {
console.log("key : " + key + " value : " + $scope.everyone[key]);
}
});
The log does contain the child objects, but it also includes all the methods. Like so
... Before this line is all the other methods.
key : $on value : function (a,c){if("loaded"==a&&b._loaded)return b._timeout(function(){c()}),void 0;if(!b._on.hasOwnProperty(a))throw new Error("Invalid event type "+a+" specified");b._on[a].push(c)} controllers.js:58
key : $off value : function (a,c){if(b._on.hasOwnProperty(a))if(c){var d=b._on[a].indexOf(c);-1!==d&&b._on[a].splice(d,1)}else b._on[a]=[];else b._fRef.off()} controllers.js:58
key : $auth value : function (a){var c=b._q.defer();return b._fRef.auth(a,function(a,b){null!==a?c.reject(a):c.resolve(b)},function(a){c.reject(a)}),c.promise} controllers.js:58
key : $getIndex value : function (){return angular.copy(b._index)} controllers.js:58
key : -JH45WOOAtnZfUZkrJb1 value : [object Object] controllers.js:58
key : -JH45YdfwptGv3y6UqyV value : [object Object] controllers.js:58
key : -JH45_zxptV_dmibyGzL value : [object Object]
Is there a way I can get just the children?
I'm doing this because my code was designed to use an array, but Firebase discourage using arrays (for values that multiple people could change). So I'm trying to loop through the firebase dictionary and copy the objects into an array on the client side. So I don't have to change too much of my code.
UPDATE: As of AngularFire 0.8.x, one can use $asArray() to obtain a sorted array of the records and this answer is no longer necessary
The correct way to iterate values in an angularFire object is by using $getIndex(). You have this in your code above, but did not utilize it in the for loop.
Since you are already using the angularFire lib (syncData is the angularFire-seed service that uses angularFire), there is no need to worry about calling $apply() or any of the other complexities of coaxing data into Angular detailed in the previous answer (which is a good response for a raw Firebase/Angular implementation).
Instead, just change your for loop to iterate the keys instead of the angularFire instance:
syncData('everyone').$bind($scope, 'everyone').then(function() {
var keys = $scope.everyone.$getIndex();
// utilizing Angular's helpers
angular.forEach(keys, function(key) {
console.log(key, $scope.everyone[key]);
});
// or as a for loop
for(var i=0, len = keys.length; i < len; i++) {
console.log(keys[i], $scope.everyone[keys[i]]);
}
});
To utilize the object in the DOM, use ng-repeat:
<ul>
<li ng-repeat="(key,user) in everyone">{{key}}, {{user|json}}</li>
</ul>
The way I do it is pretty simple, you just push all the children into an array when they arrive like this.
Everyone.on('child_added', function(snap) {
implementLogic(snap.val());
$scope.$apply();
});
function implementLogic(person) {
$scope.everyone.push(person);
if (something) {
$scope.todaysPeople.push(person);
}
if (something else) {
$scope.peopleToTest.push(person);
}
...
}
That leaves you with an array of the child objects you want.
Use ng-fire-alarm with collection: true like this:
angular.module('demo', ['ng-fire-alarm']).controller('IndexCtrl', IndexCtrl);
function IndexCtrl ($scope) {
var everyone = new Firebase(URL).child('everyone');
everyone
.$toAlarm({collection: true}) // will transform object into native array
.$thenNotify(function(everyones){ // notify you on ANY changes
$scope.everyones = everyones;
});
}