Performance issue with hundreds of references to cross

Hi there,

I’m looking for an efficient way to do some heavy (?) crossreferencing.

I’ve got ~1000 art pieces (each Piece is a subpage of an Event page, that might belong to a Festival page).
Each piece have one or more artists associated (each artist is a page, with biography, etc.). The artist(s) are linked into the piece by a pages field, and stored within an Artists page.
I’d like to list each artist (751 pages), and below each, dress a sublist of every art piece he/she is involved in.

I tried from within a controller that returns the artist list. Nothing tricky.
Then I set up a method in an Artist model to get his/her pieces.
But I face a Maximum execution time exceeded.

Do anybody have a better idea on how to get the Pieces and the Artists and cross them ?
Thanks for your help (I don’t know where/what to search in the forum; sorry if the answer is aready elsewhere)

Just to make sure I understand correctly: so you are looping through 751 artists and for each of these artists you load those 1000 art pieces and filter them by author? could you please post your code?

What is your max execution time set to?

Thanks for your reply :slight_smile:
You understood perfectly!

NB: My current computer is veeery slow. The max execution time is 30 seconds.

My controller :

$artists = page('artistes')->children()->listed()->sortBy("lastname");
return ["entries" => $artists];

My template :

<?php foreach($entries as $item): ?>        
    <?php snippet("list." . $item->intendedTemplate(), ['item' => $item]) ?>
<?php endforeach ?>

My snippet :

<h1><?= $item->title() ?></h1>
<p class="list-meta">
    <?php $pices = $item->getPieces(); ?>
    <?php foreach($pieces as $piece) :?>
        <?= $piece->title() ?>
    <?php endforeach ?>
</p>

I set up a collection (collections/pieces.php) to grap every piece :

<?php
return function ($site) {
    return $site->index()->template("piece");
};

And the model, which fails…

<?php
class ArtistPage extends Page {
    public function getPieces() {
      $artist = $this;
      $pieces = kirby()->collection("pieces");
      $artistpieces = $pieces->filterBy(function($child) use($artist){
        return $child->artists()->toPages()->has($artist);
      });
      return $artistpieces;
    }
}

This is a lot of stuff. Some suggestions:

  • consider lazy loading those artists instead of loading all at once (using Ajax)
  • use caching
  • consider using the boost plugin (Boost | Kirby CMS)
  • cache the collection for the runtime of the script
class ArtistPage extends Page {

    protected $pieces = null;

    public function getPieces() {
      if ($this->pieces === null) {
         $this->pieces = kirby()->collection("pieces");
      }
      return $this->pieces->filter(fn($child) => $child->artists()->toPages()->has($this));
    }
}

Far better !

But you’re right, that’s a lot of stuff.
I think I’ll have to change my mind (btw, the resulting page is way too long to be useful…).
Maybe should I get the pieces the ajax way – that’s one more click, but would be way faster.
I’ll try that.

Thanks a lot.

(I was thinking about how much you must know about Kirby and it’s hidden secrets. It’s staggering :slight_smile:

I hoped I could learn something, performance related.
Indeed: the option of caching the collection was a nice trick.
I solved my problem by using ajax, and loading the pieces only “on demand” (which is a nice UX, btw).

Thanks for your help.