Skip to content

Commit

Permalink
feat(firestore): Added option to include document IDs on valueChanges…
Browse files Browse the repository at this point in the history
…() (#1976)

An 'idField' option can be used with collection.valueChanges() to include the document ID on the emitted data payload.
  • Loading branch information
codediodeio authored and jamesdaniels committed May 11, 2019
1 parent 6133296 commit 7108875
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 6 deletions.
6 changes: 3 additions & 3 deletions docs/firestore/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ interface DocumentSnapshot {

There are multiple ways of streaming collection data from Firestore.

### `valueChanges()`
### `valueChanges({idField?: string})`

**What is it?** - The current state of your collection. Returns an Observable of data as a synchronized array of JSON objects. All Snapshot metadata is stripped and just the method provides only the data.
**What is it?** - The current state of your collection. Returns an Observable of data as a synchronized array of JSON objects. All Snapshot metadata is stripped and just the document data is included. Optionally, you can pass an options object with an `idField` key containing a string. If provided, the returned JSON objects will include their document ID mapped to a property with the name provided by `idField`.

**Why would you use it?** - When you just need a list of data. No document metadata is attached to the resulting array which makes it simple to render to a view.

**When would you not use it?** - When you need a more complex data structure than an array or you need the `id` of each document to use data manipulation methods. This method assumes you either are saving the `id` to the document data or using a "readonly" approach.
**When would you not use it?** - When you need a more complex data structure than an array.

**Best practices** - Use this method to display data on a page. It's simple but effective. Use `.snapshotChanges()` once your needs become more complex.

Expand Down
14 changes: 13 additions & 1 deletion src/firestore/collection/collection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { FirebaseApp, AngularFireModule } from '@angular/fire';
import { AngularFirestore } from '../firestore';
import { AngularFirestoreModule } from '../firestore.module';
import { AngularFirestoreDocument } from '../document/document';
import { AngularFirestoreCollection } from './collection';
import { QueryFn } from '../interfaces';
import { Observable, BehaviorSubject, Subscription } from 'rxjs';
Expand Down Expand Up @@ -70,6 +69,19 @@ describe('AngularFirestoreCollection', () => {

});

it('should optionally map the doc ID to the emitted data object', async (done: any) => {
const ITEMS = 1;
const { ref, stocks, names } = await collectionHarness(afs, ITEMS);
const idField = 'myCustomID';
const sub = stocks.valueChanges({idField}).subscribe(data => {
sub.unsubscribe();
const stock = data[0];
expect(stock[idField]).toBeDefined();
expect(stock).toEqual(jasmine.objectContaining(FAKE_STOCK_DATA));
deleteThemAll(names, ref).then(done).catch(fail);
})
});

it('should handle multiple subscriptions (hot)', async (done: any) => {
const ITEMS = 4;
const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS);
Expand Down
20 changes: 18 additions & 2 deletions src/firestore/collection/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,29 @@ export class AngularFirestoreCollection<T=DocumentData> {

/**
* Listen to all documents in the collection and its possible query as an Observable.
*
* If the `idField` option is provided, document IDs are included and mapped to the
* provided `idField` property name.
* @param options
*/
valueChanges(): Observable<T[]> {
valueChanges(): Observable<T[]>
valueChanges({}): Observable<T[]>
valueChanges<K extends string>(options: {idField: K}): Observable<(T & { [T in K]: string })[]>
valueChanges<K extends string>(options: {idField?: K} = {}): Observable<T[]> {
const fromCollectionRef$ = fromCollectionRef<T>(this.query);
const scheduled$ = this.afs.scheduler.runOutsideAngular(fromCollectionRef$);
return this.afs.scheduler.keepUnstableUntilFirst(scheduled$)
.pipe(
map(actions => actions.payload.docs.map(a => a.data()))
map(actions => actions.payload.docs.map(a => {
if (options.idField) {
return {
...a.data() as Object,
...{ [options.idField]: a.id }
} as T & { [T in K]: string };
} else {
return a.data()
}
}))
);
}

Expand Down

3 comments on commit 7108875

@iamsumedh91
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any way I can get these changes via npm install to my project

@iamsumedh91
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are in the docs, but I am not able to use them in the project

@EdricChan03
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iamsumedh91 These changes can be found published on the next tag.

Please sign in to comment.