I'm quite new to work with GeoFire and RXJS.
I need to display nearby users based on Geofire query. I tried so many ways, but it take long time, approx 9 segs (just 5-6 test users). How can I optimize it?
Thanks for the help in advance
In firebase
-locations
- userID
- g
- l
- 0:lat
- 1:long
- users
-userID
- firstname: "fname"
- lastname...
Geofire service
hits = new BehaviorSubject([]);
getNearLocations(radius: number, coords: Array<number>) {
this.geoFire.query({
center: coords,
radius: radius
})
.on('key_entered', (key, location, distance) => {
let hit = {
key: key,
location: location,
distance: distance,
}
let currentHits = this.hits.value
//this.hits.push(hit)
currentHits.push(hit)
this.hits.next(currentHits)
})
people.ts (Constructor)
this.locateActiveUser().then((pos) => {
this.geofire.getNearLocations(2, [pos.coords.latitude, pos.coords.longitud])
this.subscription = this.geofire.hits
.subscribe( nearUserArray => {
Promise.all(
nearUserArray.map(nearUser => {
this.afDatabase.object(`users/${nearUser.key}`).query.once('value')
.then( user => {
nearUser["user"]= user.val(); })
return nearUser
})).then( a => {
console.log("nearUserArray: ", nearUserArray);
this.nearbyUsers$ = of(nearUserArray);
})
})
})
people.html
<ion-item *ngFor="let nearby of nearbyUsers$ | async" class="item item-block item-md">
<ion-row>
<ion-col col-3 >...
</ion-col>
<ion-col col-9 (click)="navigateTo('user-profile', nearby.user)">
<ion-row>
<ion-col col-4 >
<span>A {{nearby.distance | roundNumber }} km</span>
</ion-col>
</ion-row>
<ion-row>
<h3> {{nearby.user.firstname}} {{nearby.user["lastname"]}}</h3>
</ion-row>
</ion-col>
</ion-row>
</ion-item>
Browser Console
enter image description here
So I will say that you are probably doing the best thing you could do.geofire is more like an index which you can get references to actual docs/objects in your Firebase RTDB. There are libraries for Firestore such as geofirestore (my personal baby), as well as geofirex that allow you to only make one query based on location and get the doc as well.
geofirestore is more similar to geofire in regards to how things work under the hood, and may be easier to make the transition to (if you were interested.)
Related
Hello I wanted to delete record from the realtime firebase database.I have got the key which I wanted to delete, but when I call remove function on reference is shows me error "Reference.remove failed: first argument must be a valid function."
i had refer this docs.
here is my code:
home-customer.ts
deleteLoad(load) {
this.AuthProvider.removeNote(load.key).then(() => {
this.navCtrl.setRoot('HomeCustomerPage');
});
}
home-customer.html
<ion-list *ngFor="let load of LoadMaster">
<ion-item>
Source:
{{load.Source}}
</ion-item>
<ion-item>
Destination:
{{load.Destination}}
</ion-item>
<ion-item>
Load Type:
{{load.LoadType}}
</ion-item>
<button ion-button block (click)="UpdateLoad(load.key)">
Update
</button>
<button ion-button block (click)="deleteLoad(load)">
Delete
auth.ts
removeNote(key) {
console.log('key'+key);
return firebase.database().ref(`/LoadMaster/`).remove(key);
}
It's very sad since more then 3 year no answer...I think this answer will now help to others...
`var adaRef = firebase.database().ref('users/ada');
adaRef.remove()
.then(function() {
console.log("Remove succeeded.")
})
.catch(function(error) {
console.log("Remove failed: " + error.message)
});`
More can be found Firebase documentation
I am using Angularfire2 v5. In my database I have two lists one is cartand other one is product. In cart list there is a field which contains product id and now I want a Observable that contains data for both the cart and it's product. Currently I am trying with this way
cart: Observable<any>;
constructor(public db: AngularFireDatabase) {}
ionViewDidLoad() {
this.cart = this.db.list(`/cart`)
.snapshotChanges()
.map(changes => {
return changes.map(c => {
let productObservables:Observable<any> = this.db
.list(`product/${c.key}`).snapshotChanges()
.map(m=>{
m.map(p=>({
key:c.payload.key, ...p.payload.val()
}));
return m;
});
return productObservables;
})
});
now in html using this
<ion-item *ngFor="let item of cart|async">
<ion-label>
{{item.key}}
{{item.name}}
</ion-label>
but it shows me null. How can I display both data the cart and product list in one ngFor async
Say you had a structure like this:
cart:
yyy:
productId: aaa
qty: 2
zzz:
productId: bbb
qty: 1
products:
aaa:
name: AAA
bbb:
name: BBB
Then you could map it against the other part of the db, since you already have the key I'm just using valueChanges() here.
this.cart = this.db.list(`/cart`)
.snapshotChanges()
.map(changes =>
changes.map(c => ({
key: c.payload.key,
product: this.db.object(`products/${c.payload.val().productId}`).valueChanges(),
...p.payload.val()
}))
);
The product will then be async, so you'd need to pipe that in your view too:
<ion-item *ngFor="let item of cart | async">
<ion-label *ngIf="item.product | async; let product; else loading">
{{product.name}} x {{item.qty}} {{item.key}}
</ion-label>
<ion-item>
<ng-template #loading><ion-spinner></ion-spinner></ng-template>
I'm making a social media app using Ionic with a Firebase backend that I communicate with using Angularfire2.
There's a page in my app that lists all the followers of a user by receiving a uid from the NavParams and sends this to a provider that returns a FirebaseListObservable with that user's followers.
followers-page.ts
constructor(public navCtrl: NavController, public navParams: NavParams, public util: UtilProvider, public userProvider: UserProvider, public socialProvider: SocialProvider, private zone: NgZone) {
this.name = this.navParams.get('name');
this.otherUid = this.navParams.get('uid');
this.currentUid = this.userProvider.currentUid();
}
ionViewDidLoad() {
this.zone.run(() => {
this.users = this.userProvider.getUserFollowers(this.otherUid);
});
}
followers-page.html
<ion-header>
<ion-navbar color='danger'>
<ion-title>{{name}} Followers</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-item style="background-color: #fff" *ngIf="!(users | async)">
<ion-avatar item-left>
<img src="assets/img/defaultAvatar.png">
<h2>Loading...</h2>
</ion-avatar>
</ion-item>
<user-item *ngFor="let user of users | async" [user]="user">
</user-item>
</ion-list>
</ion-content>
user-provider.ts
//Get List of followers of uid
getUserFollowers(uid) {
let users = this.af.database.list(`/users/${uid}/followers`, {
query: {
limitToFirst: 10
}
});
return users;
}
user-item.html
<ion-item style="background-color: #fff" text-wrap>
<ion-avatar item-left (click)="userProfile()">
<img [class]="user.visibility > 1 ? 'profile-pic verified' : 'profile-pic'" [src]="user?.avatar ? user.avatar : 'assets/img/defaultAvatar.png'">
</ion-avatar>
<h2 (click)="userProfile(user)">{{user?.name}}</h2>
<button ion-button item-right *ngIf="!(following)" (click)="followUser()">{{user?.followerCount}} Followers</button>
<button ion-button outline item-right icon-left *ngIf="following" (click)="followUser()">
<ion-icon name="checkmark"></ion-icon>Followed
</button>
</ion-item>
Without the limitToFirst query it displays the correct number of followers as user-items but the profile avatar and the name and the follower status are all blank. When I click on the avatar it pushes the correct user-profile page so the data is there but the DOM isn't being updated.
I have this exact same code in the discover tab of my app (without the NgZone) and it works perfectly there.
I tried it without the NgZone here as well but to no avail so I am just about completely lost as to how to get these users' info to display.
Thanks in advance!
I am creating a recipe app, I have different categories that I want to dynamically load on click. To pull recipes I have a url (http get request) which I want to extend with a string depending on what category i click on. I understand that this can be done with parameters but I do not understand how this works as I am new to angular and Ionic.
The base url would be
http://api.yummly.com/v1/api/recipes?_app_id=/////&_app_key=/////
On the end I would want to add either one of these.
396^Dairy-Free
393^Gluten-Free
391^Nut-Free
393^Wheat-Free and so on. Could someone please give me an idea on how to implement this
My HTML currently is
<ion-item [navPush] = "listingPage" detail-push>
<img src="http://placehold.it/500x500">
<h1>Glueten Free</h1>
</ion-item>
<ion-item>
<img src="http://placehold.it/500x500">
<h1>Category 2</h1>
</ion-item>
<ion-item>
<img src="http://placehold.it/500x500">
<h1>Category 3</h1>
</ion-item>
<ion-item>
<img src="http://placehold.it/500x500">
<h1>Category 4</h1>
</ion-item>
and HTTP request is
this.http.get('http://api.yummly.com/v1/api/recipes?_app_id=////&_app_key=//////')
.map(res => res.json())
.subscribe(data => {
// we've got back the raw data, now generate the core schedule data
// and save the data for later reference
console.log(data);
this.listing = data.matches;
resolve(this.listing);
});
});
Currently I only have 1 url loading on a page, but I want this to change depending on what category selected. Many thanks
You have to pass the category id when the user will select the category and then call the function and pass the category id to that function. In that function, call the http method and you can use the category id in the URL.
<button click="getData(this.value)"></button>
In ts.file
getData(cat_id : any){
......
you can use cat_id here in URL and call http method
......
}
I am getting data from firebase by using the below code and i am able to create an array using the below code.
fetchPeopleFromFirebase(){
Firebase fbUsers = this.fbObject.child("posts");
fbUsers.once("value", (snapshot) => {
if(snapshot.exists()) {
snapshot.forEach((object) => {
console.log("Current Post");
console.log(object.val());
Firebase fbUserDetails = this.fbObject.child("users");
var createdById = object.child('createdBy/_id').val();
console.log("Checking for : " + createdById)
fbUserDetails.child(createdById).once("value", (snapshot) => {
if(snapshot.exists()) {
console.log(snapshot.val());
}
});
this.posts.push(object.val());
});
}
console.log("firebase Data",this.posts);
}
}
I am storing the data in this.posts and i am trying to use it in the view like :
*ng-for="#post of posts"
But it does not display anything while data is being printed on the console
can anyone help me?
EDIT:
<ion-content>
<ion-card *ng-for="#post of posts">
<ion-item>
<ion-avatar item-left>
<img src="{{post.createdBy.avatarUrl}}">
</ion-avatar>
<h2>{{post.createdBy.firstName}} {{post.createdBy.lastName}}</h2>
<p>{{post.createdBy.profession}}</p>
</ion-item>
<ion-item>
<ion-list-header>{{post.title}}</ion-list-header>
<img src="{{post.image}}">
</ion-item>
<ion-card-content>
<p>{{post.description}}.</p>
</ion-card-content>
<ion-item actions class="demo-card">
<button primary clear item-left (click)="openLikesFollowers()">
<icon thumbs-up></icon>
<div>5 followers</div>
</button>
<button primary clear item-left (click)="openLikesFollowers()">
<icon text></icon>
<div>4 Comments</div>
</button>
<p item-left class="time-ago">
61 views
</p>
</ion-item>
<ion-item actions>
<p item-left class="time-ago">
+5 collegues are following this
</p>
</ion-item>
</ion-card>
</ion-content>