返回内部块可观察对象

时间:2017-01-31 23:09:51

标签: angular typescript rxjs angularfire2 angular2-observables

我想从过去7天内质量评级最高的Firebase数据库中返回一个对象。我使用以下的Typescript代码,首先查询过去七天内创建的所有线程,然后,在quality提取具有最高值的线程。理想情况下,我可以'#34;转换" results可观察到forEach语句的最终迭代对象。

highestWeek: Number = 0;

...

getWeeksBest(): Observable<any> {
    let now = Date.now() / 1000;
    let results = this.af.database.list('/threads', {
        query: {
            orderByChild: 'created',
            startAt: now - 604800 //One week ago
        }
    })
    .map(results => {
        results.forEach(result => {
            if (result.quality > this.highestWeek) {
                console.log(result) //Logs next highest quality thread
                this.highestWeek = result.quality       
            }
        })
    })
    results.subscribe(results => console.log(results)) //Undefined
    return results //Undefined
}

4 个答案:

答案 0 :(得分:1)

所以问题可能就是你在undefined变量的subscribe(...)回调中获得results的原因。

.map()中,您使用短箭头语法创建代码块,但这意味着您必须使用return语句。

.map(results => {
   results.forEach(result => {
       if (result.quality > this.highestWeek) {
           console.log(result) //Logs next highest quality thread
           this.highestWeek = result.quality       
       }
   });
   return results; 
})

在您的情况下,我最好使用.do()运算符而不是.map()

getWeeksBest()结束时,您将返回Observable,因此最后一行肯定不会返回undefined

getWeeksBest(): Observable<any> {
    let now = Date.now() / 1000;
    let results = this.af.database.list('/threads', {
        ...
    });
    return results;
}

答案 1 :(得分:1)

马丁是对的,你需要添加一个return语句。但请记住,Array.forEach始终返回undefined。因此,在您的情况下,您可以使用Array.map

但总的来说,我会建议这样的事情:

getAllThreads$(): Observable<any[]> {
  let now = Date.now() / 1000;
  return this.af.database.list('/threads', {
    query: {
        orderByChild: 'created',
        startAt: now - 604800 //One week ago
    }
  })
}

getWeeksBest$():Observable<number>{
  return this.getAllThreads$().map(threads => Array.isArray(threads )? threads.reduce((highestQuality, thread) => {
   let currentQuality = thread? thread.quality: 0;
   return currentQuality > highestQuality? currentQuality: highestQuality;
  }, 0): 0);
}

在您的类构造函数中的某处只订阅getWeeksBest$

答案 2 :(得分:1)

RxJS为众多运营商提供数据转换。在您的情况下,您想要检索具有最高quality值的对象,因此我们可以使用 reduce 运算符来应用maxBy()函数。

const weeks = [
    {
      quality: 1
    },
    {
      quality: 15
    },
    {
      quality: 5
    },
    {
      quality: 8
    }
  ];


//maxBy stateless function (you can see a currified function)
const maxBy = (prop) => (a, b) => a[prop] > b[prop] ? a : b;

//Fetch data and apply the maxBy when the reduce is perform over the collection
function fetchData() {
  //You can perform some async actions
  return Rx
    .Observable
    .from(weeks)
    .reduce(maxBy('quality'), 0);
}

fetchData().subscribe(x => console.log(x));

请随意查看Plunker

上的示例

答案 3 :(得分:1)

如果要返回在上周发出质量最高的线程的observable,则传递给df1 %>% mutate(X = rowSums(.[-1] == 1)) # Cluster a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 X #1 C1 0 1 1 1 0 1 1 1 1 1 1 9 #2 C2 0 1 1 1 0 1 1 1 1 1 1 9 #3 C3 0 1 0 0 0 0 1 0 0 0 0 2 #4 C4 0 1 1 1 0 1 1 1 1 1 1 9 #5 C5 0 1 1 1 0 1 1 1 1 1 1 9 运算符的函数需要返回一个值(如其他答案中所述)。

此外,如果没有线程,您需要决定应该预期的行为。结果可观察结果是否为空?或者它应该发出map

最好避免内部订阅 - 您将对每次通话进行额外订阅,并且所述订阅永远不会取消订阅。并且最好避免副作用,因为最高质量将由发出的线程提供。

你可以做这样的事情,而不是:

null

如果您想在没有线程的情况下发出getWeeksBest(): Observable<any> { let now = Date.now() / 1000; let best = this.af.database.list('/threads', { query: { orderByChild: 'created', startAt: now - 604800 //One week ago } }) // Filter out empty lists of threads, so that the resultant // observable emits nothing if there are no threads: .filter(threads => threads.length > 0) // Use Array.prototype.reduce to return the thread with the // highest quality: .map(threads => threads.reduce( (acc, thread) => thread.quality > acc.quality ? thread : acc )); return best; } ,请移除null并将filter更改为:

map