Skip to content

Instantly share code, notes, and snippets.

@isaiastavares
Created May 11, 2018 23:30
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save isaiastavares/5e8254c0fe19a22483288aacd37d7cc6 to your computer and use it in GitHub Desktop.
Save isaiastavares/5e8254c0fe19a22483288aacd37d7cc6 to your computer and use it in GitHub Desktop.
Firestore Service
import { Injectable } from '@angular/core';
import * as firebase from 'firebase/app';
import { AngularFirestore, AngularFirestoreDocument, AngularFirestoreCollection } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/switchMap';
type CollectionPredicate<T> = string | AngularFirestoreCollection<T>;
type DocPredicate<T> = string | AngularFirestoreDocument<T>;
@Injectable()
export class FirestoreService {
constructor(private db: AngularFirestore) { }
/// **************
/// Get a Reference
/// **************
public col<T>(ref: CollectionPredicate<T>, queryFn?): AngularFirestoreCollection<T> {
return typeof ref === 'string' ? this.db.collection<T>(ref, queryFn) : ref;
}
public doc<T>(ref: DocPredicate<T>): AngularFirestoreDocument<T> {
return typeof ref === 'string' ? this.db.doc<T>(ref) : ref;
}
/// **************
/// Get Data
/// **************
public doc$<T>(ref: DocPredicate<T>): Observable<T> {
return this.doc(ref).snapshotChanges().map(doc => {
return doc.payload.data() as T;
});
}
public col$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<T[]> {
return this.col(ref, queryFn).snapshotChanges().map(docs => {
return docs.map(a => a.payload.doc.data()) as T[];
});
}
/// with Ids
public colWithIds$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<any[]> {
return this.col(ref, queryFn).snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data };
});
});
}
/// with Ids
public docWithIds$<T>(ref: DocPredicate<T>): Observable<any> {
return this.doc(ref).snapshotChanges().map(a => {
// return actions.map(a => {
// });
const data = a.payload.data();
const id = a.payload.id;
return { id, ...data };
});
}
/// **************
/// Write Data
/// **************
/// Firebase Server Timestamp
get timestamp() {
return firebase.firestore.FieldValue.serverTimestamp();
}
set<T>(ref: DocPredicate<T>, data: any) {
const timestamp = this.timestamp;
return this.doc(ref).set({
...data,
updated_at: timestamp,
created_at: timestamp
});
}
update<T>(ref: DocPredicate<T>, data: any) {
return this.doc(ref).update({
...data,
updated_at: this.timestamp
});
}
delete<T>(ref: DocPredicate<T>) {
return this.doc(ref).delete();
}
public add<T>(ref: CollectionPredicate<T>, data) {
const timestamp = this.timestamp;
return this.col(ref).add({
...data,
updated_at: timestamp,
created_at: timestamp
});
}
geopoint(lat: number, lng: number) {
return new firebase.firestore.GeoPoint(lat, lng);
}
/// If doc exists update, otherwise set
upsert<T>(ref: DocPredicate<T>, data: any) {
const doc = this.doc(ref).snapshotChanges().take(1).toPromise();
return doc.then(snap => {
return snap.payload.exists ? this.update(ref, data) : this.set(ref, data);
});
}
/// **************
/// Inspect Data
/// **************
inspectDoc(ref: DocPredicate<any>): void {
const tick = new Date().getTime();
this.doc(ref).snapshotChanges()
.take(1)
.do(d => {
const tock = new Date().getTime() - tick;
console.log(`Loaded Document in ${tock}ms`, d);
})
.subscribe();
}
inspectCol(ref: CollectionPredicate<any>): void {
const tick = new Date().getTime();
this.col(ref).snapshotChanges()
.take(1)
.do(c => {
const tock = new Date().getTime() - tick;
console.log(`Loaded Collection in ${tock}ms`, c);
})
.subscribe();
}
/// **************
/// Create and read doc references
/// **************
/// create a reference between two documents
connect(host: DocPredicate<any>, key: string, doc: DocPredicate<any>) {
return this.doc(host).update({ [key]: this.doc(doc).ref });
}
/// returns a documents references mapped to AngularFirestoreDocument
docWithRefs$<T>(ref: DocPredicate<T>) {
return this.doc$(ref).map(doc => {
for (const k of Object.keys(doc)) {
if (doc[k] instanceof firebase.firestore.DocumentReference) {
doc[k] = this.doc(doc[k].path);
}
}
return doc;
});
}
/// **************
/// Atomic batch example
/// **************
/// Just an example, you will need to customize this method.
atomic() {
const batch = firebase.firestore().batch();
/// add your operations here
const itemDoc = firebase.firestore().doc('items/myCoolItem');
const userDoc = firebase.firestore().doc('users/userId');
const currentTime = this.timestamp;
batch.update(itemDoc, { timestamp: currentTime });
batch.update(userDoc, { timestamp: currentTime });
/// commit operations
return batch.commit();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment