Получить значение поля без загрузки всего узла?

11

У меня есть большое количество NID, и мне нужно одно значение поля от каждого узла. Есть ли способ избежать издержек загрузки всего узла, чтобы получить одно значение поля?

Joren
источник

Ответы:

19

Я не думаю, что есть что-то встроенное в API, но в крайнем случае вы можете просто запросить базу данных напрямую:

$entity_type = 'node';
$bundle = 'page';
$nids = array(1, 2, 3);

$field_values = db_select('field_revision_FIELD_NAME', 'f')
  ->fields('f', array('entity_id', 'FIELD_NAME_value'))
  ->condition('entity_type', $entity_type)
  ->condition('bundle', $bundle)
  ->condition('entity_id', $nids, 'IN')
  ->condition('deleted', 0)
  ->execute()
  ->fetchAllKeyed();

После выполнения этого у вас должен быть массив значений полей, введенный с помощью nid соответствующего узла.

Стоит запомнить, что имя столбца не обязательно будет FIELD_NAME_value; например, поле ссылки на узел будет иметь имя столбца FIELD_NAME_nid. Какой из них вы используете, будет зависеть от типа вашего поля.

ОБНОВИТЬ

Кажется, есть способ сделать это с помощью API, но это не очень красиво и требует ручного запроса:

// Get the field meta data for the field_id.
$field_name = 'field_something';
$field_info = field_info_field($field_name);
$field_id = $field_info['id'];

// Load up the properties from the node table.
$nids = array(1, 2, 3);
$sql = 'SELECT * FROM {node} WHERE nid IN (:nids)';
$nodes = db_query($sql, array(':nids' => $nids))->fetchAllAssoc('nid');

// Attach the single field to all nodes.
field_attach_load('node', $nodes, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

Этот метод использует преимущество $optionsпараметра field_attach_load(), указав идентификатор поля для загрузки данных. Стоит отметить, по документам:

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

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

Клайв
источник
Потрясающие. Работает отлично и НАМНОГО быстрее, чем загрузка всего узла.
Джорен
Я использовал этот подход с пользовательской сущностью для загрузки значения одного поля, но этот метод загружает все поля (и их значения), связанные с пользовательским объектом. Я что-то пропустил?
WM
Предупреждение: первый пример требует хранения полей в базе данных SQL (по умолчанию) и не совместим с альтернативными хранилищами полей. Второй должен работать (потому что он использует field_attach_load и будет работать с абстракцией хранилищ).
Бобик
@Clive, есть ли причина, по которой вы использовали field_revision_FIELD_NAME вместо field_data_FIELD_NAME? Можете ли вы объяснить, пожалуйста? Спасибо.
Сандеш Ядав
3

Я нашел немного более чистый способ, используя entityCondition и присоединение нагрузки к полю.

$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
  ->entityCondition('bundle', 'story')
  ->propertyCondition('status', 1)
  ->fieldCondition('field_story_image', 'fid', 'NULL', '!=');
$result = $query->execute();

if (isset($result['node'])) {
  $stories = $result['node'];

  // At first we need to get field's id. If you already know field id, you can ommit this step
  // Get all fields attached to a given node type
  $fields = field_info_instances('node', 'story');

  // Get id of body field
  $field_id = $fields['field_story_image']['field_id'];

  // Attach a field of selected id only to get value for it
  field_attach_load('node', $stories, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

  // Get values of our node field
  $output = field_get_items('node', $stories, 'field_story_image');
}

Из блога http://timonweb.com/loading-only-one-field-from-an-entity-or-node

gagarine
источник
0

Чтобы избежать загрузки узла один за другим с большим количеством NID, вы можете использовать его, node_load_multiple()который будет загружать сразу несколько узлов:

node_load_multiple($nids = array(), $conditions = array(), $reset = FALSE)

Обычно загрузка узлов кэшируется, и это быстро, если вы используете кэширование памяти (например, memcached), но может быть медленным, если у вас установлено слишком много модулей (например, Pathauto и т. Д.).

Другой способ - повторно использовать существующий объект, поэтому проверьте, можете ли вы загрузить его непосредственно из кэша (например, через, form_get_cacheесли он является частью формы) или из $_POSTзапроса.

Другой способ - использовать EntityFieldQueryнесколько NID, например

$query->entityCondition('entity_id', array(17, 21, 422), 'IN')

который будет получать значения непосредственно из базы данных.

kenorb
источник