我的Rx-js groupJoin

时间:2015-12-16 10:01:24

标签: javascript rxjs

以下代码:

const Rx = require('rx');

const gameRowObservable = Rx.Observable.fromArray([{
    game_id: 1,
    game_name: "game one",
}, {
    game_id: 2,
    game_name: "game two",
}]);
const playerRowObservable = Rx.Observable.fromArray([{
    game_id: 1,
    player_id: 1,
    player_name: "player one",
}, {
    game_id: 1,
    player_id: 2,
    player_name: "player two",
}, {
    game_id: 2,
    player_id: 3,
    player_name: "player three",
}, {
    game_id: 2,
    player_id: 4,
    player_name: "player four",
}]);

const rowObservable = gameRowObservable.
groupJoin(
    playerRowObservable,
    gameRow => Rx.Observable.return(gameRow.game_id),
    playerRow => Rx.Observable.return(playerRow.game_id),
    (gameRow, playerGroup) => playerGroup.toArray().map(playerGroup => Object.assign(gameRow, {
        player_list: playerGroup
    }))
).mergeAll();

rowObservable.subscribe(row => console.log(row));

产生以下结果:

{ game_id: 1, game_name: 'game one', player_list: [] }
{ game_id: 2, game_name: 'game two', player_list: [] }

我想得到这个结果:

[{
    game_id: 1,
    game_name: "game one",
    player_list: [{
        game_id: 1,
        player_id: 1,
        player_name: "player one",
    }, {
        game_id: 1,
        player_id: 2,
        player_name: "player two",
    }]
}, {
    game_id: 2,
    game_name: "game two",
    player_list: [{
        game_id: 2,
        player_id: 3,
        player_name: "player three",
    }, {
        game_id: 2,
        player_id: 4,
        player_name: "player four",
    }]
}]

所以我基本上希望每场比赛的球员都是阵列属性。我做错了什么?

3 个答案:

答案 0 :(得分:1)

我无法提供有效的解决方案,但我希望我能帮助您走上正确的道路。

正如您在groupJoin的文档中所看到的,第二个和第三个参数用于确定要分组的持续时间而不是属性值

你实际上是通过重叠进行分组,即从gameRowA的发射开始,在发出下一个gameRow之前发出的任何playerRows都与gameRowA分组。由于您不希望任何花哨的分组,您的持续时间选择器只是您的源可观察量。见jsbin

const rowObservable = gameRowObservable.
groupJoin(
    playerRowObservable,
    gameRow => gameRowObservable,
    playerRow => playerRowObservable,
    (gameRow, playerGroup) => playerGroup.toArray().map(playerGroup => Object.assign(gameRow, {
        player_list: playerGroup
    }))
).mergeAll();

rowObservable.subscribe(row => console.log(row));

答案 1 :(得分:0)

如果您无法根据之前给出的示例(http://rxwiki.wikidot.com/101samples#toc39)设置代码,则此处为jsfiddle(http://jsfiddle.net/t2bjy03p/2/):

var gameRowObservable
    = Rx.Observable.fromArray([
                                {game_id : 1, game_name : "game one" },
                                {game_id : 2, game_name : "game two" }
                              ]);
var playerRowObservable
    = Rx.Observable.fromArray([
                                {game_id : 1, player_id : 1, player_name : "player one"},
                                { game_id : 1, player_id : 2, player_name : "player two"},
                                {game_id : 2, player_id : 3, player_name : "player three"},
                                {game_id : 2, player_id : 4, player_name : "player four"}
                              ]);

var rowObservable = gameRowObservable.
    groupJoin(
    playerRowObservable,
    function () {return Rx.Observable.merge(gameRowObservable, playerRowObservable).last()},
    function () {return Rx.Observable.never()},
    function ( gameRow, playerRowObservable ) {
      return playerRowObservable
          .filter(function ( playerRow ) {
                    return playerRow.game_id === gameRow.game_id
                  })
          .toArray()
          .map(function(player_list){return Object.assign(gameRow, {
        player_list: player_list})})
    })
    .mergeAll();

rowObservable.subscribe(function ( row ) {console.log(row)});

在控制台中,您应该看到确切的预期输出。

一些解释:

  • groupJoin根据持续时间选择器进行分组。对于这个复杂的运算符,标准文档非常密集,我认为这里更清楚:http://reactivex.io/documentation/operators/join.html
  • 很难用文字清楚解释,所以这里有一个澄清事情的测试:https://searchcode.com/codesearch/view/86405588/(只查看第一个GroupJoinOp_Normal_I
  • 简而言之,您定义时间窗口,根据您定义的选择器功能,这些窗口中重合的项目将配对在一起。该函数有两个参数:第一个将从第一个observable接收项,第二个将是一个observable,其元素将是同一窗口中第二个observable的项(实际上看看测试,它更清楚)。 / LI>
  • 所以在这里,你要配对任何后续玩家的任何game_id。所以基本上你不想关闭你的分组窗口,直到两个源可观察量都已完成。因此,持续时间选择器的这种特殊选择
  • 然后将代码分组到包含player_list的对象中。
  • groupJoin返回的observable将发出一个只有一个元素的observable,该元素在发出该元素后很快就会完成。
  • mergeAll展平所观察到的可观察物

可能会稍微短一些。我没有太多时间去调查,但是如果你这样做,请在这里发布结果。我还没有看到很多关于这个运营商的问题,所以任何信息都是受欢迎的。

答案 2 :(得分:0)

暂时我使用非rx解决方案。如果我想要的东西不可能与RxJS一起使用,那么我觉得持续时间实际上是指持续时间。

仅供参考我现在使用的解决方案有点类似:

const gameRows = [{
    game_id: 1,
    game_name: "game one",
}, {
    game_id: 2,
    game_name: "game two",
}];
const playerRows = [{
    game_id: 1,
    player_id: 1,
    player_name: "player one",
}, {
    game_id: 1,
    player_id: 2,
    player_name: "player two",
}, {
    game_id: 2,
    player_id: 3,
    player_name: "player three",
}, {
    game_id: 2,
    player_id: 4,
    player_name: "player four",
}];

gameRows.sort((a, b) => a.game_id - b.game_id);
playerRows.sort((a, b) => a.game_id - b.game_id);

/*
in the thing I am building, I get the two lists from a database and sort them
in the database!
*/

const playerRowCount = playerRows.length;

var playerRowIndex = 0;
const rows = gameRows.map(gameRow => {
    const player_list = [];
    while (playerRowIndex < playerRowCount && playerRows[playerRowIndex].game_id === gameRow.game_id) {
        player_list.push(playerRows[playerRowIndex]);
        playerRowIndex++;
    }
    return Object.assign({
        player_list
    }, gameRow);
});

rows.forEach(row => console.log(row));

如果存在有效的RxJS解决方案,我仍然很好奇。