Javascript RXJS扩展运算符

Javascript RXJS扩展运算符,javascript,rxjs,rets,Javascript,Rxjs,Rets,我正在做一个房地产网站,使用RETS 我试图从RETS服务器执行的查询是有限的,在循环中运行它,增加我的偏移量,直到我拥有所有数据。在运行查询并找到计数值之前,我不知道计数是多少 我曾尝试使用expand,但我不知道它到底是如何工作的。尝试了多种方法,甚至使用了旧的while循环,while不能使用.then方法。自从我在Angular 4中使用RXJS以来,我就转向了它 这是以快递方式完成的。我最终需要运行corn作业来获取更新的属性,但我的问题是获取所有数据,如果计数高于偏移量,则每次都增加

我正在做一个房地产网站,使用RETS

我试图从RETS服务器执行的查询是有限的,在循环中运行它,增加我的偏移量,直到我拥有所有数据。在运行查询并找到计数值之前,我不知道计数是多少

我曾尝试使用expand,但我不知道它到底是如何工作的。尝试了多种方法,甚至使用了旧的while循环,while不能使用.then方法。自从我在Angular 4中使用RXJS以来,我就转向了它

这是以快递方式完成的。我最终需要运行corn作业来获取更新的属性,但我的问题是获取所有数据,如果计数高于偏移量,则每次都增加偏移量。例如,运行一个偏移量为1、限制为500的查询。这里的总数是1690。所以下一步我的偏移量是:

var offset = 1;
var limit = 500;

var list = new Promise(function (resolve, reject) {
  rets.getAutoLogoutClient(config.clientSettings, (client) => {
    var results = client.search.query(SearchType, Class, Query, {
      limit: limit,
      offset: offset
    });
    resolve(results);
  });
});

var source = Rx.Observable.fromPromise(list);

source.subscribe(results => console.log(results.count));
一旦我有了数据,我需要将其保存到MongoDB。我已经成功地做到了。它只是想找到一种不用手动设置偏移量就能获取所有数据的方法

请注意,服务器限制为2500,是的,我可以一次获取所有这些数据,但也有其他数据,例如媒体,它们的数据量可能远远超过2500


有什么建议吗

这实际上是RxJS的一个相当常见的用例,因为有很多分页数据源,或者在一次可以请求的内容上受到限制的数据源

我的两分钱

在我看来,
expand
可能是最好的运算符,因为您正在对未知数据源进行分页,并且至少需要一个查询才能确定最终计数。如果您知道要查询多少数据,一个更简单的选择是使用类似于
mergeScan
的东西,但我离题了

建议的解决方案

这可能需要一点努力才能让你的头脑清醒过来,所以我在任何可能的地方都添加了注释来分解这一切是如何工作的。注意,我还没有实际测试过这个,所以请原谅我的语法错误

offset += limit
//任何一个查询的常量限制
常数限值=500;
//RxJS帮助器方法,将异步调用包装成可观察的
//我是基于我所看到的你的样品,这使我相信
//这应该行得通。
const clientish=Rx.Observable.bindCallback(rets.getAutologotClient);
//围绕查询调用的方法包装器,用于包装结果承诺
//推迟。
常量queryish=(客户端,参数)=>
//注意这里使用defer是故意的,因为查询返回
//承诺将立即开始执行,这将阻止这种行为
//并在订阅时强制执行。
Rx.Observable.defer(()=>client.search.query(SearchType,Class,query,params));
//这就完成了实际的扩展功能
//注意,这是一个高阶函数,因为客户端和参数
//可在不同时间使用
常量扩展器=(客户端)=>({limit,count})=>
//调用查询方法
querysh(客户端,{limit,count})
//重新映射结果,更新偏移量、计数并转发整个
//包下游
.map(结果=>({
极限,
count:results.count,
偏移量:偏移量+限制,
结果
}));
//通过构造客户端启动流
clientish(config.clientSettings)
.switchMap(客户端=>
//这是初始调用的参数
Rx.Observable.of({极限,偏移量:0})
//使用客户端调用expander函数
//第二个参数是最大并发性,如果需要,您可以更改它
.扩展(扩展器(客户端),1)
//Expand将继续递归,除非您告诉它停止
//一旦偏移量超过计数,这将停止执行,即
//所有数据
.takeWhile(({count,offset})=>offset/*使用结果做一些事情*/);
这就是我在这里尝试过的东西。我仍然在调整这个过程中。所以我想做的是进一步细分searchQuery。我不确定我是否应该经过observer.next,所以我要弄清楚在再次安装返回的searchQuery之前映射和执行的位置。我不确定takeUntil是否会接受正确或错误的答案。我所需要做的就是将这些数据保存到mongodb中。所以我想我可以像这样把我的save方法放在那里,但我还是想弄明白这一点


注意:当还有更多数据时,results.maxRowsExceeded返回true。因此,一旦maxRows返回false,它将停止,并且所有数据都已提取。

这不起作用。switchMap不是一个函数。takeWhile有语法错误,需要更好地组合rets客户端内容。@JoshuaScott您使用的是哪个版本的RxJS?我使用的是RxJS 5
// Your constant limit for any one query
const limit = 500;

// RxJS helper method that wraps the async call into an Observable
// I am basing this on what I saw of your sample which leads me to believe
// that this should work. 
const clientish = Rx.Observable.bindCallback(rets.getAutoLogoutClient);

// A method wrapper around your query call that wraps the resulting promise
// into a defer.
const queryish = (client, params) =>
  // Note the use of defer here is deliberate, since the query returns
  // a promise that will begin executing immediately, this prevents that behavior
  // And forces execution on subscription.
  Rx.Observable.defer(() => client.search.query(SearchType, Class, Query, params));

// This does the actual expansion function
// Note this is a higher order function because the client and the parameters
// are available at different times
const expander = (client) => ({limit, count}) => 
  // Invoke the query method
  queryish(client, {limit, count})
    // Remap the results, update offset and count and forward the whole 
    // package down stream
    .map(results => ({
      limit, 
      count: results.count, 
      offset: offset + limit, 
      results
    }));


// Start the stream by constructing the client
clientish(config.clientSettings)
  .switchMap(client =>
     // This are the arguments for the initial call
     Rx.Observable.of({limit, offset: 0})
       // Call the expander function with the client
       // The second argument is the max concurrency, you can change that if needed
       .expand(expander(client), 1)

       // Expand will keep recursing unless you tell it to stop
       // This will halt the execution once offset exceeds count, i.e. you have
       // all the data
       .takeWhile(({count, offset}) => offset < count)

       // Further downstream you only care about the results
       // So extract them from the message body and only forward them
       .pluck('results')
  )
  .subscribe(results => /*Do stuff with results*/);
const retsConnect = Rx.Observable.create(function(observer) {
  rets.getAutoLogoutClient(config.clientSettings, client => {
    return searchQuery(client, 500, 1, observer);
  });
});

function searchQuery(client, limit, offset, observer) {
  let currentOffset = offset === undefined || offset === 0 ? 1 : offset;
  return client.search.query(SearchType, Class, Query, {limit: limit, offset: currentOffset})
    .then(results => {
      offset += limit;
      observer.next(results.maxRowsExceeded);
      if (results.maxRowsExceeded) {
        console.log(offset);
        return searchQuery(client, limit, offset, observer);
      } else {
        console.log('Completed');
        observer.complete();
      }
    });
}

retsConnect.subscribe(val => console.log(val));