ГлавнаяРазноеВложенные мета-запросы с WP_Meta_Query

Вложенные мета-запросы с WP_Meta_Query

Если вы работаете со сложной структурой данных в WordPress, то вас приятно удивят новые возможности вложенных запросов с WP_Meta_Query в версии 4.1.

Ранее мы уже писали о произвольных полях в WP_Query, где мы рассмотрели несколько примеров работы с параметром meta_query класса WP_Query. Этот параметр позволяет производить выборку записей по их мета-данным, что может быть полезно для каталога товаров, сайта агентства недвижимости и т.д.

В новой версии WordPress 4.1 (которая выйдет в декабре 2014) данный параметр позволяет выполнять вложенные запросы для более сложной выборки данных. Чтобы понять как это работает, легче всего рассмотреть пример.

Предположим что мы выбираем автомобиль. Если цена автомобиля более $5000, то мы согласны только на красный цвет кузова, но если автомобиль дешевле $5000, то мы готовы рассмотреть и другие цвета: красный, зеленый, синий и желтый. С помощью вложенных структур в WP_Meta_Query наш запрос будет выглядеть следующим образом:

$query = new WP_Query( array(
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'relation' => 'AND',
            array(
                'key'     => 'price',
                'value'   => 5000,
                'type'    => 'numeric',
                'compare' => '>=',
            ),
            array(
                'key'     => 'color',
                'value'   => 'red',
            ),
        ),
        array(
            'relation' => 'AND',
            array(
                'key'     => 'price',
                'value'   => '5000',
                'type'    => 'numeric',
                'compare' => '<',
            ),
            array(
                'key'     => 'color',
                'value'   => array( 'red', 'green', 'blue', 'yellow' ),
                'compare' => 'IN',
            ),
        ),
    ),
) );

Здесь в параметре meta_query мы указываем два вложенных запроса с отношением (relation) OR. Это означает, что в выборку попадут записи, которые удовлетворяют требованиям хотя бы одного из двух запросов указанных далее в массивах.

Первый запрос:

array(
    'relation' => 'AND',
    array(
        'key'     => 'price',
        'value'   => 5000,
        'type'    => 'numeric',
        'compare' => '>=',
    ),
    array(
        'key'     => 'color',
        'value'   => 'red',
    ),
),

Он имеет вложенную структуру с двумя подзапросами и отношением AND, т.е. для вхождения в выборку данного запроса, должны выполниться оба его подзапроса: цена автомобиля равна или более 5000, и цвет равен красному.

Второй запрос:

array(
    'relation' => 'AND',
    array(
        'key'     => 'price',
        'value'   => '5000',
        'type'    => 'numeric',
        'compare' => '<',
    ),
    array(
        'key'     => 'color',
        'value'   => array( 'red', 'green', 'blue', 'yellow' ),
        'compare' => 'IN',
    ),
),

Он также имеет вложенную структуру и два подзапроса с отношением AND, выбирает все автомобили стоимостью менее 5000 и красным, зеленым, синим или желтым цветом кузова.

Таким образом, вложенные структуры в WP_Meta_Query дают нам возможность выполнять более сложную выборку по мета-полям в базе данных WordPress. Стоит отметить, что подобный синтаксис доступен также для классов WP_Tax_Query и WP_Date_Query. До версии 4.1 подобные запросы приходилось строить самостоятельно на языке SQL, например с помощью фильтра posts_clauses.

Несмотря на расширенные возможности запросов по мета-данным в 4.1, не стоит забывать о производительности базы данных. Ведь тип поля meta_value в таблице wp_postmeta является текстовым, а его преобразование в числовой или любой другой тип во время поиска и сравнения означает, что серверу MySQL необходимо просканировать все строки с определенным ключом, без возможности использования дополнительных вспомогательных индексов.

Для большого количества данных подобные запросы могут стать медленными, и мы рекомендуем смотреть в сторону внешних систем индексирования и поиска данных, например Sphinx или Elasticsearch.

Подписаться на рассылку

Подписаться → Подпишитесь на бесплатную рассылку журнала WP Magazine и получайте новости, события, подборки тем и плагинов, уроки, советы и многое другое в мире WordPress!

  • versusbassz

    WordPress становится лучше. Ура! :)

  • MrClon

    Не хотите написать про плагин Posts 2 Posts? Очень интересная штука. Услышал о ней на недавней конфе и на проникся что сразу обежал делать ней один проект.

    А невозможность выборок по mata_value (выборки без индекса — не серьёзно) это печально. Может есть какие-то пути обхода этого ограничения, кроме внешнего индексатора? Например создать отдельную таблицу, с более строгими ограничениями и держать в ней те произвольные поля по которым нужны быстрые выборки. Конечно придётся держать где-то список таких полей, впиливать много хаков в ядро что-бы конструкция работала прозрачно, да и вообще архитектурно это не красиво… Но мне кажется в виде плагина это было-бы оправдано.

    • Несколько лет назад пробовали создать ряд вспомогательных таблиц с определенными типами и индексами, а также ряд триггеров, которые наполняли эту таблицу, и ряд фильтров в плагине, которые направляли туда запросы вместо CAST(). Все работало, но прикрутить Sphinx оказалось проще, да и по производительности гораздо быстрее.

    • MrClon

      А работа со Сфинксом прозрачна, или это отдельное API?

      Кажется триггеры тут это перебор, логику было-бы удобнее реализовать на стороне WP.
      if ($meta_key in $list_moved_keys) {return get_from_ext_table($meta_key);} else…
      Только наверное много что переопределят придётся.

      • Это отдельный API, к нему необходимо обращаться с запросом, а в ответ он выдаст список из идентификаторов записей, которые можно уже использовать с аргументом post__in в объектах WP_Query.

  • Дамир

    Как же надоело всплывающее окно с предложением подписаться на новости WP. Учитывая, что и так подписан на RSS и пришёл из RSS

    • Дамир, если ваш браузер поддерживает куки, то это окно вы должны видеть всего один раз. Если не сложно, не могли бы вы отправить нам на wpmagru@gmail.com все куки к домену wpmag.ru и их значения в вашем браузере?

  • Владимир Петрозаводский

    прямо шаг вперед по сравнению с прошлыми фитчами :) ставлю свой плюс

  • Стас

    Как при помощи Sphinx или Elasticsearch. можно осуществлять поиск по метаполям?

    • Это детали настройки Sphinx и Elasticsearch, эти поля просто нужно добавить в индекс и при обращении к API по ним выполнять поиск.

      • Стас

        Понятно. Эти дополнения только осуществляют поиск, сортировать с ними не получится к примеру по дате или по цене?

        • Можно и сортировать.