Excluindo campos vazios (nulos) ao usar a condição de consulta EntityFieldQuery

31

É possível selecionar todas as entidades cujo campo xyz está vazio?

Eu tentei algo assim:

->fieldCondition('field_name', 'value', NULL, 'IS NOT NULL');

No entanto, isso não parece funcionar.

Alguma ideia?

David Barratt
fonte

Respostas:

19

Se você olhar na página de documentação do fieldCondition , verá o seguinte aviso:

Observe que entidades com valores de campos vazios serão excluídas dos resultados EntityFieldQuery ao usar esse método.

A verificação da existência ou não de um campo foi adicionada ao entityFieldQuery no Drupal 8, mas infelizmente não será suportada para o Drupal 7 .

Existem vários métodos para conseguir isso:

  1. Usando uma tag e hook_query_TAG_alter, conforme mencionado por @Clive, consulte o comentário 4 sobre a questão do Drupal para obter um exemplo;
  2. Primeiro, consulte todas as entradas que não sejam NULL, depois todas as entradas, exceto as anteriores, conforme descrito na resposta de @ seddonym e no comentário 5 sobre o problema do Drupal ;
  3. Você pode escrever sua consulta usando SelectQuery rathen que EntityfieldQuery, como tal:

_

$q = db_select('node', 'n');
$q->fields('n', array('type'))
  ->condition('n.type', 'my_node_type', '=')
  ->addJoin('LEFT', 'field_data_field_my_field', 'f', 'f.entity_id = n.nid');
$q->isNull('f.value');
$r = $q->execute();
Alice Heaton
fonte
15

Você pode usar != NULL, mas não pode usar = NULLpor algum motivo.

Esta é a minha solução alternativa.

  //Get all the entities that DO have values
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'MY_TYPE')
    ->fieldCondition('field_MY_FIELD', 'value', 'NULL', '!=');
  $result = $query->execute();

  if (is_array(@$result['registration'])) {
    //Now get all the other entities, that aren't in the list you just retrieved
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'MY_TYPE')
      ->entityCondition('entity_id', array_keys($result['MY_TYPE']), 'NOT IN');
    $result_two = $query->execute(); 
  }
seddonym
fonte
10

De acordo com a documentação, você pode usar null e isnull; apenas tem uma maneira específica de escrevê-lo.

$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
  ->entityCondition('bundle', 'article')
  ->propertyCondition('status', 1)
  ->fieldCondition('field_news_types', 'value', 'spotlight', '=')
  ->fieldCondition('field_photo', 'fid', 'NULL', '!=')
  ->fieldCondition('field_faculty_tag', 'tid', $value)
  ->fieldCondition('field_news_publishdate', 'value', $year. '%', 'like')
  ->range(0, 10)
  ->addMetaData('account', user_load(1)); // run the query as user 1

$result = $query->execute();

if (isset($result['node'])) {
  $news_items_nids = array_keys($result['node']);
  $news_items = entity_load('node', $news_items_nids);
}
giorgio79
fonte
9

A resposta curta é que diretamente, não, você não pode (consulte EntityFieldQuery não suporta isNull ou isNotNull ). Se bem me lembro, esse é um efeito colateral do fato de que EntityFieldQueryusa apenas INNER JOINs para juntar tabelas.

Existe uma solução alternativa, porém, que envolve o uso hook_query_TAG_alter()e a adição de uma tag à sua EntityFieldQuery, há um exemplo no último comentário na página que eu vinculei acima.

Clive
fonte
5

No Drupal 7, verifique a seguinte solução proposta aqui :

Registre a tag para alterar a instância da consulta:

<?php
/**
 * Implements hook_query_TAG_alter()
 */
function MYMODULE_query_node_is_not_tagged_alter(QueryAlterableInterface $query) {
  $query->leftJoin('field_data_field_tags', 'o', 'node.nid = o.entity_id AND o.entity_type = :entity_type');
  $query->isNull('o.field_tags_tid');
}
?>

Obs .: Essa alteração da tag de consulta funciona apenas para o tipo de entidade "nó". Não confunda "tags de campo" relacionadas ao vocabulário "Tags", pois pode haver outras como "Categorias".

Obtenha todos os nós que ainda não foram marcados usando EntityFieldQuery, veja o método addTag ():

<?php
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
  ->entityCondition('bundle', 'news')
  ->addTag('node_is_not_tagged')
  ->propertyCondition('status', 1);
$result = $query->execute();
?>

Outro exemplo:

  $result = $query
    ->entityCondition('entity_type', 'node')
    ->propertyCondition('type', 'my_content_type')
    ->fieldCondition('field_mine_one', 'value', '', '<>')
    ->fieldCondition('field_mine_two', 'value', '', '<>')
    ->addTag('my_custom_tag')
    ->deleted(FALSE)
    ->propertyOrderBy('changed', 'DESC')
    ->range(0, $my_range_value)
    ->execute();

Então eu implementei, hook_query_TAG_alteraproveitando o fato que my_custom_tagé definido apenas por mim:

/**
 * Implements hook_query_TAG_alter()
 */
function MYMODULE_query_TAG_alter(QueryAlterableInterface $query) {
  $query->leftJoin('field_data_field_other', 'o', 'node.nid = o.entity_id');
  $query->isNull('o.field_other_value');
}

Outro exemplo:

<?php
  //Get all the entities that DO have values
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'MY_TYPE')
    ->fieldCondition('field_MY_FIELD', 'value', 'NULL', '!=');
  $result = $query->execute();

  if (is_array(@$result['registration'])) {
    //Now get all the other entities, that aren't in the list you just retrieved 
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'MY_TYPE')
      ->entityCondition('entity_id', array_keys($result['MY_TYPE']), 'NOT IN');
    $result_two = $query->execute();  
  }
?>

Exemplo mais completo abaixo, que carrega vários nós na tarefa cron, que esvazia referências de termos de taxonomia e aplica algumas mudanças:

/**
 * Implements hook_cron().
 */
function MYMODULE_cron() {
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', 'property')
    ->propertyOrderBy('changed', 'DESC')
    ->addTag('type_is_null')
    ->range(0,50); // Maximum of 50.
  $result = $query->execute();

  if (!empty($result['node'])) {
    $nids = array_keys($result['node']);
    $nodes = node_load_multiple($nids);

    foreach ($nodes as $node) {
      // do_some_stuff($node);
    }
  }
}

/**
 * Implements hook_query_TAG_alter()
 */
function MYMODULE_query_type_is_null_alter(QueryAlterableInterface $query) {
  $query->leftJoin('field_data_field_foo', 'f', 'node.nid = f.entity_id AND f.entity_type = :entity_type');
  $query->isNull('f.field_foo_tid'); // Check name by SQL: DESC field_data_field_foo

  $query->leftJoin('field_data_field_bar', 'b', 'node.nid = b.entity_id AND b.entity_type = :entity_type');
  $query->isNull('b.field_bar_tid'); // Check name by SQL: DESC field_data_field_bar
}
kenorb
fonte
3

Você precisa agrupar Nulo entre aspas.

->fieldCondition('field_name', 'value', 'NULL', '!=');
Sharique
fonte
2

Por favor me corrija se eu estiver errado. Parece que ele simplesmente precisa ser

$query->fieldCondition('field_name');

excluir todos os nós com um field_namecampo vazio o_O

Testado em Drupal version >= 7.43.

leymannx
fonte
Isso realmente funciona. As respostas mais votadas foram erradas para mim (não conseguiram exibir um erro, mas estavam quebrando tudo).
Joren 25/01