Random sorting

As I remember, FQL does not provide a random function for security reasons. But it should be possible to provide some random value from the client code and sort by that. Am I correct?

How to sort ‘randomly’

I think you are correct in your assumption. The way to sort documents randomly could be to store a random value via your app’s code (JS, C#, …) e.g.

client.query(Create(
    Collection('posts'),
    { data: { 
        title: 'something interesting...',
        sortvalue: Math.random()
   } },
  )
)

And then create an index on this sort value.

CreateIndex({
    name: 'random-index',
    source: Collection('posts'),
    values: [{ field: ['data', 'sortvalue'] }],
  })

Of course, the random ordering will no longer change and always be the same random ordering.
You could get creative with that if you want and either over time change these values or provide multiple random values:

client.query(Create(
    Collection('posts'),
    { data: { 
        title: 'something interesting...',
        sortvalues: {
           v1: Math.random(),
           v2: Math.random()
        }
   } },
  )
)

And then create multiple indexes and pick your index randomly :wink:

Now I just realized, that for many cases it should be possible and good enough to use Pseudorandom number generator

function random(seed: number) {
  const nextSeed = (1839567234 * seed + 972348567) % 8239451023
  return nextSeed;
}

const seed = 1;
const randomNumber1 = random(seed);
const randomNumber2 = random(randomNumber1);

I looked into random sorting (on each query) and came with such solution:

  1. Create random number and store it when writing document.
  2. Generate random number on the client (on every query) and send it to Function
  3. Function is calling Filter on index and compares if random number stored is bigger than random number from client.

If anyone have better solution let us now.

It should be plenty possible to implement @Daniel_Steigerwald’s pseudorandom number generator directly in FQL where you would provide access to a UDF Create function but not the standard one. Daniel’s links are rather esoteric, but the code there is an easy example of what can be done. The seed value can be stored in the data for the function, and interestingly enough, a function can update itself!

This implements the code above in FQL for a UDF named “srng”

Query(
  Lambda(
    [],
    Let(
      {
        seed: Select(["data", "seed"], Get(Function("srng")), 1),
        nextSeed: Modulo(
          Add(Multiply(1839567234, Var("seed")), 972348567),
          8239451023
        ),
        functionUpdate: Update(Function("srng"), {
          data: { seed: Var("nextSeed") }
        })
      },
      Var("nextSeed")
    )
  )
)

UPDATE 2024-05-02

WARNING: mutating schema in an unbounded manner like this is highly discouraged. History retention on schema is infinite, so updates like this will be problematic for reads and storage. Additionally, reading a resource and updating it transactionally is prone to contention when it occurs often. An operation like this would basically be limited to about 5 requests concurrent requests.

One alternative could be to save the seed in a document owned by the caller. That way you avoid both history issues as well as contention with other callers (assuming the caller does not make many concurrent requests)

2 Likes