meta_query с meta оценивает, как сериализируют массивы

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

<p> 
    <label for="latitude">Latitude:</label><br /> 
    <input type="text" id="latitude" name="coordinates[latitude]" class="full-width" value="" /> 
</p> 
<p>     
    <label for="longitude">Longitude:</label><br /> 
    <input type="text" id="longitude" name="coordinates[longitude]" class="full-width" value="" /> 
</p>

По любой причине мне понравилась идея наличия исключительной postmeta записи для каждого метаполя. На save_post рычаг, я сохраняю данные как так:

update_post_meta($post_id, '_coordinates', $_POST['coordinates']);

Я сделал это, потому что у меня есть три метаполя, и мне нравится просто иметь 3 значения postmeta для каждого сообщения; однако, я теперь понял потенциальную проблему с этим. Я могу хотеть использовать WP_Query, чтобы только выйти, определенные сообщения основывали эти значения meta. Например, я могу хотеть получить все сообщения, которые имеют значения широты выше 50. Если у меня были эти данные в базе данных индивидуально, возможно, с помощью ключа latitude, Я сделал бы что-то как:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>'
        )
    )
 );
$query = new WP_Query( $args );

Так как у меня есть широта как часть _coordinates postmeta, это не работало бы.

Так, мой вопрос, там способ использовать meta_query для запросов сериализированного массива как, я имею в этом сценарии?

37
09.05.2011, 05:06
6 ответов

Нет, это не возможно, и могло даже быть опасно.

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

$args = array(
    'post_type' => 'my-post-type',
    'meta_key' => '_coordinates',
    'posts_per_page' => -1
 );
$query = new WP_Query( $args );
if($query->have_posts()){
    while($query->have_posts()){
        $query->the_post();
        $c = get_post_meta($post->id,'_coordinates',true);
        add_post_meta($post->ID,'_longitude',$c['longitude']);
        add_post_meta($post->ID,'_latitude',$c['latitude']);
        delete_post_meta($post->ID,'_coordinates',$c);
    }
}

Затем Вы сможете запросить, как Вы хотите с отдельными ключами

Если необходимо сохранить несколько долгот и несколько широт, можно сохранить, несколько отправляют meta с тем же именем. Просто используйте третий параметр get_post_meta, и это возвратит их всех как массив

Почему Вы не можете запросить внутренние сериализированные данные?

MySQL видит его как просто строка и не может разбить его на структурированные данные. Разбивание его в структурированные данные точно, что выше делает код

Вы можете запрашивать для частичных блоков даты, но это будет супер ненадежно, дорого, медленно, и очень хрупко с большим количеством пограничных случаев. Сериализированные данные не предназначаются для SQL-запросов и не отформатированы регулярным и постоянным способом.

Кроме затрат на частичные поиски строки, запросы meta сообщения являются медленными, и сериализированные данные могут измениться в зависимости от вещей, таких как длина содержания, делая ищущий невероятно дорогой, если не невозможный в зависимости от значения Вы ищете

Примечание по Хранению Записей/Объектов/Объектов как Сериализованные объекты в Meta

Вы могли бы хотеть сохранить запись транзакции в сообщении meta или некоторый другой вид структуры данных в пользователе meta, затем столкнуться с проблемой выше.

Решение здесь не состоит в том, чтобы выломать его в отдельное сообщение meta, но понять, что это никогда не должен был быть meta для начала, но пользовательский тип сообщения. Например, журнал или запись могут быть пользовательским типом сообщения с исходным сообщением как родитель, или присоединенный через термин таксономии

Объекты безопасности и сериализованные объекты

Хранить сериализировало объекты PHP через serialize функция может быть опасной, который неудачен, поскольку передача объекта к WordPress будет означать, что это сериализируется. Это вызвано тем, что, когда объект десериализовывается, объект создается, и весь его след, методы и конструкторы выполняются. Это не могло бы походить на грандиозное предприятие, пока пользователю не удается стащить тщательно обработанный вход, ведя к удаленному выполнению кода, когда данные считаны с базы данных и десериализованы WordPress.

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

37
19.02.2020, 21:54
  • 1
    Для людей, проходящих мимо, не прекращайте читать: более полезный (и недавний) ответы найдены ниже –  Erenor Paz 13.04.2017, 13:07
  • 2
    Что, если у меня есть массив идентификаторов для сохранения - и они каждый не представляют различный ключ, я мог сохранить их под таким как 'широта' и т.д., это - всего один ключ для всех (такой, сохраняя отношения и т.д.). Что сделать затем? решение @rabni? –  trainoasis 16.06.2017, 10:52
  • 3
    Можно сохранить ключ несколько раз, пары значения ключа не уникальны. Что касается отношений, это - то, для чего taxonomies при использовании meta, чтобы отобразить несколько вещей на что-то, поместить их в термин таксономии вместо этого –  Tom J Nowell♦ 19.06.2017, 20:31

У меня есть тот же вопрос. Возможно, Вам нужен параметр 'типа'? Проверьте этот связанный вопрос: Пользовательский Полевой Запрос - Значение Meta является Массивом

Возможно, попытка:

    $args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>',
            'type' => 'numeric'
        )
    )
    );
-1
19.02.2020, 21:54
  • 1
    Спасибо за предложение, но это не вполне, что я после. Проблема состоит в том, что значение, которому я пытаюсь соответствовать, является частью массива, который сериализируется в базе данных. –  tollmanz 13.05.2011, 06:10
  • 2
    Да, Вы правы. Я попробовал это этим утром, и это не работало на меня также. У меня есть та же проблема. Хранение значения метаклавиши как массив. Я начинаю думать, что это не может быть сделано, и мне, возможно, вместо этого придется сохранить их как отдельные meta поля с тем же именем... и просто справиться с удалением/обновлением их правильно. –  user4356 13.05.2011, 18:05
  • 3
    @user4356..., это точно, что я собираюсь сделать. Я надеялся сократить количество строк, которые я вставлю для каждого сообщения, но я предполагаю, что это не возможно. –  tollmanz 14.05.2011, 22:15

Я столкнулся с чем-то подобным при использовании Волшебного Полевого плагина. Это могло бы добиться цели

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => $values_serialized,
            'compare' => '>'
        )
    )
);
-1
19.02.2020, 21:54
  • 1
    Спасибо за предложение! Я думаю, что это настолько близко, как можно добраться, но это не будет на самом деле работать, потому что сравнение сериализированного массива к другому сериализированному массиву не делает имевшего смысла, если я не искал точное совпадение. –  tollmanz 13.05.2011, 06:08
  • 2
    Затем это не должно быть отмечено как корректный ответ, и безответственно из Вас сделать так. Корректный ответ таким образом был бы 'нет, Это не возможно' –  Tom J Nowell♦ 20.08.2012, 18:14
  • 3
    Согласитесь, также WP обрабатывает сериализацию для Вас, serialize() не требуется в этом экземпляре... –  Adam 20.08.2012, 19:11
  • 4
    На самом деле @seth-stevenson ответ является большим при выполнении точно, что он сказал, с помощью "Волшебные Поля" плагин. Поскольку тот плагин сериализирует определенный тип данных по умолчанию, это - лучший способ сделать Точное совпадение. –  zmonteca 09.01.2013, 07:02
  • 5
    @TomJNowell! Просто взял меня 5 месяцев ;) –  tollmanz 18.01.2013, 00:15

Вы действительно собираетесь потерять способность запросить Ваши данные любым эффективным способом при сериализации записей в базу данных WP.

Сохранение общей производительности и усиление, Вы думаете, что достигаете сериализацией, не будут примечательными ни до какой главной степени. Вы могли бы получить немного меньший размер базы данных, но стоимость транзакций SQL будет большой, если Вы когда-нибудь запрашиваете те поля и пытаетесь сравнить их каким-либо полезным, значимым способом.

Вместо этого сохраните сериализацию для данных, которые Вы не намереваетесь запросить в той природе, но вместо этого только получили бы доступ пассивным способом прямым вызовом API WP get_post_meta() - от той функции можно распаковать сериализированную запись для доступа к ее свойствам массива также.

На самом деле присвоенный значение истинных как в;

$meta = get_post_meta( $post->ID, 'key', true );

Возвратит данные как массив, доступный, чтобы Вы выполнили итерации согласно нормальному.

Можно сфокусироваться на другой оптимизации базы данных/сайта, такой как кэширование, CSS и минификация JS и использование таких сервисов как CDN, если Вы требуете. Назвать только некоторые.... Кодекс WordPress является хорошей начальной точкой для раскрытия больше по той теме: ЗДЕСЬ

10
19.02.2020, 21:54

Этот пример действительно помог мне. Это специально для плагина S2Members (который сериализирует пользовательские метаданные). Но это позволяет Вам запрашивать часть сериализированного массива в meta_key.

Это работает при помощи функции MySQL REGEXP.

Вот источник

Вот код, который запрашивает всех пользователей, живущих в США. Я легко изменил его для запросов одного из моих пользовательских регистрационных полей и имел его работающий в мгновение ока.

  <?php
global $wpdb;
$users = $wpdb->get_results ("SELECT `user_id` as `ID` FROM `" . $wpdb->usermeta . 
          "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_custom_fields' AND 
           `meta_value` REGEXP '.*\"country_code\";s:[0-9]+:\"US\".*'");
if (is_array ($users) && count ($users) > 0)
    {
        foreach ($users as $user)
            {
                $user = /* Get full User object now. */ new WP_User ($user->ID);
                print_r($user); /* Get a full list of properties when/if debugging. */
            }
    }
?>
1
19.02.2020, 21:54

Я только что имел дело с сериализированными полями и мог запросить их. Не используя meta_query, но с помощью SQL-запроса.

global $wpdb; 

$search = serialize('latitude').serialize(50);

$query = $wpdb->prepare("SELECT `post_id`
FROM `wp_postmeta`
WHERE `post_id` IN (SELECT `ID` FROM `wp_posts` WHERE `post_type` = 'my-post-type')
AND `meta_key` = '_coordinates'
AND `meta_value` LIKE '%s'",'%'.$search.'%');

$ids = $wpdb->get_col($query);

$args = array(
    'post__in' => $ids
    'post_type' => 'team' //add the type because the default will be 'post'
);

$posts = get_posts($args);

Запрос сначала ищет сообщение с соответствием post_type, таким образом, сумма записей wp_postmeta будет меньше для фильтрации. Затем я добавил где оператор для сокращения строк далее путем фильтрации на meta_key

Идентификаторы заканчиваются приятно в массиве по мере необходимости для get_posts.

PS. MySQL v5.6 или выше необходим для хорошей подпроизводительности запросов

3
19.02.2020, 21:54

Теги

Похожие вопросы