Reputation: 1255
I'm using Firebase in my Angular2 app to retrieve data from my database. What's the easiest was of returning an array of unique values in the nested tags list? I.e. in my example I want to return ["Sport", "Adventure", "Music"]
where the 2nd "Adventure" is omitted.
{
"images": {
"image1": {
"path": "path",
"date": 43534532123,
"tags": {
0: "Sport",
1: "Adventure"
}
},
"image2": {
"path": "path",
"date": 43534532123,
"tags": {
0: "Music",
1: "Adventure"
}
}
}
I tried this approach but it seems to split the elements from the first image only
return this.af.database.list('/photos/user')
.map(photos => photos.map(photo => photo.tags))
.concatAll()
.distinct()
However, this approach yields the correct output but as a separate stream of the unique tags instead of as one array
return this.af.database.list('/photos/user')
.map(photos => photos.map(photo => photo.tags))
.mergeAll()
.mergeAll()
.distinct()
Upvotes: 1
Views: 1277
Reputation: 5964
UPDATE
I assumed in the original answer that it was a stream with the individual items. Later the OP clarified it is a stream of a list of photos. In this case we use Array#reduce
instead of Observable#reduce
.
return this.af.database.list('/photos/user')
.map(photos => photos.map(photo => photo.tags)
.reduce((allTags, current) => {
return allTags.concat(
current.filter(item => allTags.indexOf(item) === -1))
}, []))
ORIGINAL ANSWER
distinct
over an observable returns unique individual values in an stream, but is not the operator we want here. It's is possible to produce a sequence with all the tags, each one as a separate value, but then we would need to regroup them again.
We can use instead reduce
, quite similar to the Array counterpart. It takes an initial value ([]
) and accumulates the others. We built a list with the individual values on each iteration. After the reduce we have an array of unique tags.
Notice that .list()
should complete the observable for it to work.
return this.af.database.list('/photos/user')
.map(photos => photos.map(photo => photo.tags))
.reduce((allTags, current) => {
return allTags.concat(
current.filter(item => allTags.indexOf(item) === -1))
}, [])
Upvotes: 2