Czy pobrać wartość pola bez ładowania całego węzła?

11

Mam dużą liczbę identyfikatorów NID i potrzebuję jednej wartości pola z każdego węzła. Czy jest jakiś sposób, aby uniknąć obciążenia związanego z ładowaniem całego węzła w celu uzyskania jednej wartości pola?

Joren
źródło

Odpowiedzi:

19

Nie sądzę, że w API jest coś wbudowanego, ale w mgnieniu oka można po prostu zapytać bezpośrednio bazę danych:

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

Po uruchomieniu powinieneś mieć tablicę wartości pól, wpisanych przez numer identyfikacyjny odpowiedniego węzła.

Warto pamiętać, że nazwa kolumny niekoniecznie musi być FIELD_NAME_value; na przykład pole odwołania do węzła miałoby nazwę kolumny FIELD_NAME_nid. To, którego użyjesz, będzie zależeć od typu pola.

AKTUALIZACJA

Wygląda na to, że można to zrobić za pomocą interfejsu API, ale nie jest ładny i nadal wymaga ręcznego zapytania:

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

Ta metoda wykorzystuje ten $optionsparametr field_attach_load(), określając identyfikator pola, dla którego mają zostać załadowane dane. Warto zauważyć, według dokumentów:

Zwróć uwagę, że zwrócone jednostki mogą zawierać dane dla innych pól, na przykład jeśli są one odczytywane z pamięci podręcznej.

Wygląda więc na to, że kod ładuje dodatkowe dane pola, ale wszystko inne niż pole określone przez Ciebie będzie pochodzić z pamięci podręcznej.

Clive
źródło
Niesamowite. Działa idealnie i DUŻO szybciej niż ładowanie całego węzła.
Joren
Użyłem tego podejścia z jednostką użytkownika, aby załadować wartość pojedynczego pola, ale ta metoda ładuje wszystkie pola (i ich wartości) powiązane z obiektem użytkownika. Czy coś brakuje?
WM
Ostrzeżenie: pierwszy przykład wymaga przechowywania pól w bazie danych SQL (domyślnie) i nie jest kompatybilny z alternatywnymi zapisami pól. Drugi powinien działać (ponieważ używa field_attach_load i będzie działał z abstrakcją pamięci).
Bobík,
@Clive, czy jest jakiś powód, dla którego użyłeś field_revision_FIELD_NAME zamiast field_data_FIELD_NAME? Czy możesz wyjaśnić? Dzięki.
Sandesh Yadav,
3

Znajduję nieco czystszy sposób, używając encji Warunek i podłączanie obciążenia pola.

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

Z posta na blogu http://timonweb.com/loading-only-one-field-from-an-entity-or-node

gagarine
źródło
0

Aby uniknąć ładowania węzła jeden po drugim, posiadającego dużą liczbę NID, możesz użyć, node_load_multiple()który załaduje wiele węzłów za jednym razem:

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

Zwykle ładowanie węzłów jest buforowane i jest szybkie, jeśli używasz buforowania pamięci (jak memcached), ale może być powolne, jeśli masz zbyt wiele zainstalowanych modułów (takich jak Pathauto itp.).

Innym sposobem jest ponowne użycie istniejącego obiektu, więc sprawdź, czy możesz załadować go bezpośrednio z pamięci podręcznej (np. Poprzez, form_get_cachejeśli jest to część formularza) lub z $_POSTżądania.

Innym sposobem jest użycie EntityFieldQueryz wieloma identyfikatorami NID, np

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

który pobierze wartości bezpośrednio z bazy danych.

kenorb
źródło