загрузка связанных документов в доктрину ODM приводит к слишком большому количеству запросов - PullRequest
4 голосов
/ 14 марта 2019

Я застрял, пытаясь уменьшить количество запросов к базе данных на веб-API.В моей базе 3 коллекции: playground, widget, token

На одной игровой площадке много виджетов, на одном виджете - один токен.Каждое отношение использует referencesOne / referenceMany.

Итак, вот мои упрощенные модели

/**
 * @MongoDB\Document()
 */
class Widget
{
    /**
     * @MongoDB\ReferenceOne(targetDocument="Token", inversedBy="widgets")
     */
    protected $token;

    /**
     * @MongoDB\ReferenceOne(targetDocument="Playground", inversedBy="widgets")
     */
    protected $playground;
}

/**
 * @MongoDB\Document()
 */
class Playground
{
    /**
     * @MongoDB\ReferenceMany(targetDocument="Widget", mappedBy="playground")
     */
    protected $widgets;
}

/**
 * @MongoDB\Document()
 */
class Token
{
    /**
     * @MongoDB\ReferenceMany(targetDocument="Widget", mappedBy="token")
     */
    protected $widgets;
}

Мне нужно использовать полную игровую площадку со всеми ее виджетами и токенами, но по умолчанию Doctrineвыполняет слишком много запросов: один для получения игровой площадки (хорошо), другой для получения всех виджетов отображения (хорошо) и для каждого виджета один запрос для получения токена (не нормально).Есть ли способ запросить все токены одновременно, вместо того, чтобы получать их один за другим?

Я посмотрел на простое число, но, похоже, это не решило мою проблему ...

Есть лииным способом, кроме использования построителя запросов и гидратации всех объектов вручную, чтобы уменьшить количество запросов?

Редактировать: Как я добавил в своем комментарии, мне нужно получить игровую площадкуи все его зависимости как большой объект, json кодирует его и возвращает в ответ.

Сейчас я делаю запрос к игровой площадке и кодирую его, но Doctrine заполняет зависимости неэффективным способом: сначалаэто запрос для получения playgroung, тогда есть еще один запрос для получения связанных виджетов, и есть один запрос для каждого виджета, чтобы получить его токен.

Поскольку одна игровая площадка может иметь сотни виджетов, это приводитк сотням запросов к базе данных.

То, что я ищу, это способ сообщить Doctrine, чтобы получить все эти данные, используя только 3 запроса (один для получения списка воспроизведения, нае, чтобы получить виджеты и один, чтобы получить токены).

Ответы [ 2 ]

1 голос
/ 31 марта 2019

update : поскольку ArrayCollection в $playground должен содержать все виджеты, по крайней мере, в качестве прокси-объектов (или должен загружаться при обращении), следующее должно работать для получения всех требуемых токенов ...

Поскольку менеджер документов сохраняет все управляемые объекты, он должен предотвращать возникновение дополнительных запросов.(Обратите внимание на пропущенное задание из execute).

$qb = $dm->createQueryBuilder('Token')->findBy(['widget' => $playground->getWidgets()]);
$qb->getQuery()->execute();

, вдохновленное этой страницей о том, как избежать ловушек доктрины - точка 5

старый / оригинальный ответ

Я не совсем знаком с mongodb, tbh, но согласно рекомендациям по заливке , вы должны быть в состоянии несколько комфортно увлажнить свою игровую площадку с помощью:

$qb = $dm->createQueryBuilder('Widget')->findBy(['playground' => $playground]);
$qb->field('token')->prime(true);
$widgets = $qb->getQuery()->execute();

однако я могу ошибаться.

0 голосов
/ 01 апреля 2019

Что насчёт этого:

class Foo
{
    /** @var \Doctrine\ORM\EntityManagerInterface */
    private $entityManager;

    public function __construct(\Doctrine\ORM\EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function getAll(): array {
        $qb = $this->entityManager->createQueryBuilder();
        return $qb
            ->select('p,t,w')
            ->from(Playground::class, 'p')
            ->join(Widget::class, 'w')
            ->join(Token::class, 't')
            ->getQuery()
            ->getResult();
    }
}

По крайней мере с бэкэндом mysql это решает проблему "n + 1". Не уверен насчет MongoDB, однако.

...