Почему Rose::DB::Object sort_by RAND() не выполняет то, что я ожидаю?

Я не могу заставить его работать. Я использую этот запрос:

my $user_questions 
    = RoseDB::UserSecurityQuestion::Manager->get_user_security_questions(
        query        => [
                          'user.username' => $username,
                        ],
        with_objects => ['User','SecurityQuestion'],
        sort_by      => 'RAND()',
        limit        => 2,
    );

Когда я включаю отладку в Rose::DB::Object::Manager, я вижу, что предложение order:

ORDER BY t1.id, RAND()

Где это t1.id приходящий из? И любая идея, как я могу исправить ORDER BY быть просто RAND()?

1 ответ

Решение

Из документации для sort_by параметр:

При выборе подобъектов (через require_objects или with_objects), которые связаны через отношения "один ко многим" или "многие ко многим", первое условие в предложении порядка сортировки должно быть столбцом в первичной таблице (t1). Если это условие не выполняется, список столбцов первичного ключа будет автоматически добавлен в начало предложения порядка сортировки.

Это необходимо для правильного связывания подобъектов с их родительскими объектами.

Если вы хотите изменить это поведение, вы можете использовать (пока что недокументированное) no_forced_sort логический параметр.

my $user_questions =
  RoseDB::UserSecurityQuestion::Manager->get_user_security_questions(
    ...
    sort_by        => 'RAND()',
    no_forced_sort => 1);

Но весьма вероятно, что это приведет к тому, что подобъекты будут связаны с неверными родительскими объектами. То, что вам нужно, чтобы сделать эту работу, является своего рода, который детерминистически основан на уникальной характеристике t1, но в остальном случайен. То есть, somefunc(t1.id) будет случайным, но всегда будет возвращать один и тот же результат для данного значения t1.id, сохраняя всех детей с правильными родителями.

Очевидный (и, вероятно, гораздо более прагматичный) подход заключается в получении всех вопросов безопасности для пользователя. $username а затем просто случайным образом выбрать два:

my $user_questions =
  RoseDB::UserSecurityQuestion::Manager->get_user_security_questions(
    query        => [ 'user.username' => $username ],
    with_objects => ['User','SecurityQuestion']);

use constant NUM_RANDOM_QUESTIONS => 2;

my @questions;

for(1 .. NUM_RANDOM_QUESTIONS)
{
  last unless(@$user_questions);
  push(@questions, splice(@$user_questions, int(rand(@$user_questions)), 1));
}

Теперь у вас есть (максимум) NUM_RANDOM_QUESTIONS случайно выбранные вопросы в @questions,

Другие вопросы по тегам