Store records and shuffle

Silverstripe Version: 4.1

Question:

I’m trying to get a bunch of DB records into an array and then shuffle them.

I’ve truncated this code to just be one set of 3 questions, in reality I need to get 4 sets of random questions from different categories.

        $allQuestions = Question::get();

        $random = DB::get_conn()->random(); 

        $questions = $allQuestions
            ->filter(['CategoryID' => 1, 'TypesID' => 1])
            ->sort($random)
            ->limit(3); 

        foreach ($questions as $question)
        {
            echo 'Question: '.$question->ID.'<br/>';
        }

        $questions->sort("rand()");

        echo 'After shuffle <br/>';
        
        foreach ($questions as $question)
        {
            echo 'Question: '.$question->ID.'<br/>';
        }

Out put

Question: 5
Question: 2
Question: 4
After shuffle
Question: 5
Question: 2
Question: 3

Why has 4 changed to 3? I’m expecting to see the same 5,2,4 in a different order. I assume this is to do with SS ORM “lazy loading” but it was already looped in the first loop.

Do I have to use arraylist and all the non native stuff or?

As far as I know, the sort() method won’t do what you’re expecting (ie. shuffle the instance of the datalist you already have). Instead, it will return a new datalist.

So you probably need to do:

$sortedQuestions = $questions->sort("rand()");

foreach ($sortedQuestions as .....

As an aside, rather than specifying the rand() method, you’re safer using the following (it stops your code being MySQL-specific):

$random = DB::get_conn()->random(); 
$sortedQuestions = $questions->sort($random);

https://docs.silverstripe.org/en/4/developer_guides/model/data_model_and_orm/#sorting

Thanks for replying, I do appreciate it!

I’ve read the docs - that’s how I got as far as I did…

I’ve used your rand change with no effect:

		$allQuestions = Question::get();

		$random = DB::get_conn()->random(); 

		$questions = $allQuestions
			->filter(['CategoryID' => 1, 'TypesID' => 1])
			->sort($random)
			->limit(3);	

		foreach ($questions as $question)
		{
			echo 'Question: '.$question->ID.'<br/>';
		}

		$random = DB::get_conn()->random(); 
		$sortedQuestions = $questions->sort($random);

		echo 'After shuffle <br/>';
		
		foreach ($sortedQuestions as $question)
		{
			echo 'Question: '.$question->ID.'<br/>';
		}

Out put:

Question: 4
Question: 1
Question: 2
After shuffle
Question: 1
Question: 2
Question: 3

In other words, no change

The results would suggest that it’s re-running the query. You could possibly confirm this by adding ?showqueries=inline to the URL (you need to be in dev mode)

@Tim Yeah, it is re-running the query again.

Even this reruns the query:

        $questions = $allQuestions
            ->filter(['CategoryID' => 1, 'TypesID' => 1])
            ->sort("rand()")
            ->limit(3); 

        foreach ($questions as $question) echo 'Question: '.$question->ID.'<br/>';

        $questions->sort("rand()");

        echo 'After shuffle <br/>';
        
        foreach ($questions as $question) echo 'Question: '.$question->ID.'<br/>';

Results in:
Question: 2
Question: 3
Question: 4

After shuffle

Question: 5
Question: 2
Question: 1