¿Recuperar un valor de campo sin cargar todo el nodo?

11

Tengo una gran cantidad de NID y necesito un valor de campo de cada nodo. ¿Hay alguna forma de evitar la sobrecarga de cargar todo el nodo para obtener un valor de campo?

Joren
fuente

Respuestas:

19

No creo que haya nada integrado en la API, pero en un apuro podría consultar la base de datos directamente:

$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();

Después de ejecutarlo, debe tener una matriz de valores de campo, marcados por el nid de su nodo respectivo.

Vale la pena recordar que el nombre de la columna no será necesariamente FIELD_NAME_value; por ejemplo, un campo de referencia de nodo tendría un nombre de columna de FIELD_NAME_nid. El que use dependerá de su tipo de campo.

ACTUALIZAR

Parece que hay una manera de hacerlo con la API, pero no es bonita y aún implica una consulta manual:

// 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));

Ese método aprovecha el $optionsparámetro field_attach_load()al especificar una ID de campo para cargar datos. Vale la pena señalar, según los documentos:

Tenga en cuenta que las entidades devueltas pueden contener datos para otros campos, por ejemplo, si se leen desde un caché.

Por lo tanto, puede parecer que el código carga datos de campo adicionales, pero cualquier otra cosa que no sea el campo que especificó vendrá de la memoria caché.

Clive
fuente
Increíble. Funcionó perfectamente y MUCHO más rápido que cargar todo el nodo.
Joren
He utilizado este enfoque con la entidad del usuario para cargar el valor de un solo campo, pero este método carga todos los campos (y sus valores) asociados con el objeto del usuario. ¿Me estoy perdiendo de algo?
WM
Advertencia: El primer ejemplo requiere almacenar campos en la base de datos SQL (predeterminado) y no es compatible con almacenamientos de campos alternativos. El segundo debería funcionar (porque usa field_attach_load y funcionará con la abstracción de almacenamientos).
Bobík
@Clive, ¿hay alguna razón por la que usaste field_revision_FIELD_NAME en lugar de field_data_FIELD_NAME? ¿Puede usted explicar por favor? Gracias.
Sandesh Yadav
3

Encuentro una manera un poco más limpia usando una entidadCondition y Field Attach Load.

$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');
}

De la publicación del blog http://timonweb.com/loading-only-one-field-from-an-entity-or-node

gagarina
fuente
0

Para evitar cargar el nodo uno por uno que tiene una gran cantidad de NID, puede usar el node_load_multiple()cual cargará múltiples nodos de una vez:

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

Normalmente, los nodos de carga se almacenan en caché y es rápido si está utilizando el almacenamiento en memoria caché (como memcached), pero podría ser lento si tiene demasiados módulos instalados (como Pathauto, etc.).

Otra forma es reutilizar el objeto existente, así que verifique si puede cargarlo directamente desde la memoria caché (por ejemplo, a través de form_get_cachesi es parte del formulario) o desde la $_POSTsolicitud.

Otra forma es usar EntityFieldQuerycon múltiples NID, por ejemplo

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

que buscará los valores directamente de la base de datos.

kenorb
fuente