检索字段值而不加载整个节点?


11

我有大量的NID,并且每个节点都需要一个字段值。有什么方法可以避免加载整个节点以获得一个字段值的开销?

Answers:


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

该方法通过指定要为其加载数据的字段ID来利用$options参数field_attach_load()。根据文档,值得注意的是:

请注意,返回的实体可能包含其他字段的数据,例如,如果它们是从缓存中读取的。

因此,该代码可能似乎已加载了额外的字段数据,但是除了您指定的字段之外,其他任何内容都将来自缓存。


太棒了 完美地工作,比加载整个节点快得多。
Joren 2012年

我已将这种方法与用户实体一起使用,以加载单个字段的值,但是此方法将加载与用户对象关联的所有字段(及其值)。我想念什么吗?
WM

警告:第一个示例要求将字段存储在SQL数据库中(默认),并且与备用字段存储不兼容。第二个应该工作(因为它使用field_attach_load并将与存储抽象一起工作)。
Bobík

@Clive,您是否有任何理由使用field_revision_FIELD_NAME而不是field_data_FIELD_NAME?你能解释一下吗?谢谢。
Sandesh Yadav

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


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')

这将直接从数据库中获取值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.