Search for "sibling lines" in an ordered list

I have an FQL that organizes my documents by score of several players with their respective teams. As in the example below.

q.Map(
  q.Paginate(

      q.Match(
        q.Index('statistics_highest_scorers_by_season_id'),
        5 // seasonId
      ),
    {size: 30, after}
  ),
  q.Lambda(
    ["score", "player_id", "team_id"],
    {
      player: q.Select(
        'data',
        q.Get(
          q.Match(
            q.Index('players_by_season_and_player'),
            5,
            q.Var('player_id')
          )
        )
      ),
      team: {
        name: q.Select(['data', 'name'],
            q.Get(q.Match( q.Index('team_by_season_and_team_id'), 5, q.Var('team_id')))
        ),
        image: q.Select(['data', 'image'],
          q.Get(q.Match( q.Index('team_by_season_and_team_id'), 5, q.Var('team_id')))
        )
      },
      score: q.Var("score"),
    }
  )
)

My “after” comes from another variable that is inserted there. It is not a reference, but a score from the sorted list (which I found strange, but apparently in my list in descending order where the first field is the score, I have to page using this information).

But the real point of my question is about a next step I need. This FQL so far is working (I just don’t know if it’s the best method).

I now need to get a player from this list with his score and the 2 players with scores next to him in this ranking (the one before in the ranking and the one after) and not the whole list.

Is there a more correct way to do this without having to bring all the information at once and map it in javascript.

Hi @Roco!

You have the index sorted by scores, so you can paginate the entry immediately before and immediately after the current entry.

To do that as a separate operation you can do the following

Let(
  {
    player_ref: Ref(Collection("players"), "101"),
    player: Get(Var("player_ref"),
    score: Select(["data", "score"], Var("player")),
    player_id: Select(["data", "id"], Var("player")),

    // Using an `after` cursor returns results inclusive of the cursor
    player_above: Select(
      ["data", 1],
      Paginate(
        Match(Index("statistics_highest_scorers_by_season_id"), 5),
        { size: 2, after: [Var("score"), Var("player_id")] }
      ),
      null
    ),

    // Using a `before` cursor returns results exclusive of the cursor
    player_below: Select(
      ["data", 0],
      Paginate(
        Match(Index("statistics_highest_scorers_by_season_id"), 5),
        { size: 1, before: [Var("score"), Var("player_id")] }
      ),
      null
    )
  },
  {
    player: Var("player"),
    player_above: ???, // get the player from the index entry
    player_below: ???  // get the player from the index entry
  }
)

To add the above/below player to the existing result in your example, then you could use Reduce to iterate over the list and inject the players. But at that point, the additional compute might not be worth doing inside of Fauna, and be better to do in your app – the result will still be sorted.

Hi @Roco. Were you able to work this out? Let us know if you still have any questions.

Cheers!