I’m looking for a hand with making an observable contain only distinct records.
I’m using the observable in an angular mat-autocomplete with an async pipe and querying firebase with the user’s typed-in values to bring back the list of options.
The template mat-autocomplete:
<mat-form-field appearance="outline">
<mat-label>Customer Name</mat-label>
<input
type="text"
placeholder="Start typing customer name"
formControlName="customerName"
matInput
[matAutocomplete]="customerName"
/>
<mat-autocomplete
#customerName="matAutocomplete"
[displayWith]="displayFn"
>
<mat-option
*ngFor="let option of filteredPurchaseOrders | async"
[value]="option"
(onSelectionChange)="autofill(option)"
>
{{ option.customerName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
Subscribing to valuechanges of the input field:
this.filteredPurchaseOrders =
this.purchaseOrderForm.controls.customerName.valueChanges.pipe(
filter((val) => typeof val !== 'object' && val !== null),
debounceTime(400),
switchMap((value) => {
return this.purchaseOrdersService.searchCustomerDetails(value);
})
);
}
From the purchaseOrdersService is returned the observble:
searchCustomerDetails(searchString: string): Observable<CustomerDetails[]> {
const start = searchString.toLowerCase();
const end = start.replace(/.$/, (c) =>
String.fromCharCode(c.charCodeAt(0) + 1)
);
return this.firestore
.collection('purchaseOrders', (ref) =>
ref
.where('customerNameLower', '>=', start)
.where('customerNameLower', '<', end)
)
.get()
.pipe(
map((results) => {
return results.docs.map((po) => {
var data = po.data() as CustomerDetails;
return {
customerAddress: data.customerAddress,
customerBusinessIdent: data.customerBusinessIdent,
customerBusinessIdentType: data.customerBusinessIdentType,
customerName: data.customerName,
};
});
})
);
}
This is working fine – the search returns the documents that match the customer name as typed in by the user and the mat-autocomplete options show the values. The issue is that, as should be fairly obvious, if there are many records that have the same customer details then there will be many identical-looking results in the observable.
I need to be able to filter the observable so that it only contains distinct records of the CustomerDetails object.
Can anyone help me with the appropriate RXJS pipe operations (or some other solution) to get this done?
3
Answers
Fixed it with an a little ES6
Let’s assume the unique field is
customerName
. We can use ahashMap
to filter out duplicates.RxJS ->
distinct()
https://rxjs.dev/api/operators/distinct