Получение строк, созданных до выбранной - PullRequest
0 голосов
/ 02 марта 2020

Мне было интересно узнать, как лучше всего подсчитать все строки, созданные до выбранной. Прямо сейчас я определил метод доступа, который выглядит следующим образом:

// In the model
public function getPositionAttribute() {
    return self::where([
        // Some other condition
        ['created_at', '<', $this->created_at->toDateTimeString()]
    ])->count();
}

// In the code
$model->position

Он работает правильно, но меня беспокоит 2 вещи:

  1. Это плохая практика для вызова self на модели? Мне как-то кажется.
  2. При вызове в foreach это, очевидно, генерирует запрос для каждого элемента, который далек от оптимального. Есть ли способ реорганизовать это так, чтобы его можно было загружать в одном запросе?

Бонус: я полностью отбросил идею сохранить столбец с каким-то индексом, потому что это изначально казалось невозможным поддерживать, например. когда запись удалена, все остальные должны как-то сдвинуть позицию. Должен ли я пересмотреть это? Есть ли лучший способ?

1 Ответ

0 голосов
/ 03 марта 2020

Я уверен, что использование self здесь - это "лучшая практика", потому что именно так было разработано ключевое слово.

Что касается рефакторинга, я лично не могу думать об оптимизации запроса как есть. но вместо этого вы можете создать функцию, которая предварительно загружает все позиции, а затем использовать ее как обычно. Предполагая, что ваша модель имеет уникальный ключ 'id', а затем вы передаете коллекцию моделей, вы можете попробовать что-то вроде этого:

public static function populateOrderPositions($modelCollection){
  // Optimize this query to include your "other condition"
  $idCollection = Model::orderBy('created_at') // this will make it in the order of creation
      ->pluck('id'); // this will only retrieve the id field

  // This array will contain an array with the model object ids as key and a numeric position (starts at 0)
  $positionArr = $idCollection->flip()->all();

  // Then just load all the position into the object and return it.
  return $modelCollection->map(function($modelObj) use ($positionArr){
      return $modelObj->position = $positionArr[$modelObj->id] + 1; // +1 because array key starts at 0
    };
}

Вам также необходимо настроить код атрибута для использования загруженного атрибут вместо игнорирования загруженного атрибута, например, так:

public function getPositionAttribute() {
    return $this->attributes['position'] ?? self::where([
        // Some other condition
        ['created_at', '<', $this->created_at->toDateTimeString()]
    ])->count();
}

С этими изменениями вы можете предварительно заполнить позицию и затем использовать ее без необходимости запрашивать базу данных.

Эти коды непроверенный, поскольку я не знаю, как ваша модель и запрос будут структурированы, и это скорее пример. Также вам нужно сравнить производительность с исходным кодом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...