23

I have a content type that has a entity reference field that allows users to add multiple taxonomy terms in that field. I'm attempting to perform queries that grab nodes that have a specific set of taxonomy terms within that field.

Using one value in that field works fine, like so.

    $query = \Drupal::entityQuery('node')
        ->condition('status', NODE_PUBLISHED)
        ->condition('type', 'custom_type')
        ->condition('custom_taxonomy', 2)
        ->sort('field_last_name', DESC);

Where 2 is the id of the term I'm searching for. However when I attempt to search for nodes that contain two specific terms like so,

    $query = \Drupal::entityQuery('node')
        ->condition('status', NODE_PUBLISHED)
        ->condition('type', 'custom_type')
        ->condition('custom_taxonomy', [2,8])
        ->sort('field_last_name', DESC);

I receive the error

Invalid parameter number: number of bound variables does not match number of tokens:

I've also attempted

    $query = \Drupal::entityQuery('node')
        ->condition('status', NODE_PUBLISHED)
        ->condition('type', 'custom_type')
        ->condition('custom_taxonomy', [2,8], 'IN')
        ->sort('field_last_name', DESC);

Which doesn't fail, but doesn't provide the intended results. It displays every node that has either term 2 OR term 8. Instead of term 2 AND term 8 as intended. How would I perform a query that checks if a node has multiple specific values in an entity reference field?

0

4 Answers 4

34

Use two separate andConditionGroup():

$query = \Drupal::entityQuery('node')
  ->condition('status', NODE_PUBLISHED)
  ->condition('type', 'custom_type');
$and = $query->andConditionGroup();
$and->condition('custom_taxonomy', 2);
$query->condition($and);
$and = $query->andConditionGroup();
$and->condition('custom_taxonomy', 8);
$query->condition($and);
$result = $query->execute();

This works no matter how many terms are in the field or in which delta they are.

Edit

This results in this SQL:

SELECT base_table.vid AS vid, base_table.nid AS nid
FROM 
{node} base_table
INNER JOIN {node_field_data} node_field_data ON node_field_data.nid = base_table.nid
INNER JOIN {node__custom_taxonomy} node__custom_taxonomy ON node__custom_taxonomy.entity_id = base_table.nid
INNER JOIN {node__custom_taxonomy} node__custom_taxonomy_2 ON node__custom_taxonomy_2.entity_id = base_table.nid
WHERE  (node_field_data.status = '1') AND (node_field_data.type = 'custom_type') AND( (node__custom_taxonomy.custom_taxonomy_target_id = '2') )AND( (node__custom_taxonomy_2.custom_taxonomy_target_id = '8') )
5
  • 1
    He tried an equivalent code above and it returned no values, did you check that this code works?
    – Eyal
    Commented Jan 23, 2017 at 20:54
  • 1
    Yes, it works for the standard article and tags field filled with multiple tags.
    – 4uk4
    Commented Jan 23, 2017 at 20:55
  • 1
    Maybe my suggestion failed because I wrote it like so $and->condition('custom_taxonomy', [2], 'IN'), $and->condition('custom_taxonomy', [8], 'IN')
    – Eyal
    Commented Jan 23, 2017 at 20:57
  • 4
    That doesn't matter, just tested it, works with 'IN' too. What makes the difference is the two separate AND groups.
    – 4uk4
    Commented Jan 23, 2017 at 21:02
  • 4
    Nice, didn't know this works. Makes sense, as this forces multiple joins internally.
    – Berdir
    Commented Jan 23, 2017 at 21:33
9

To do complex queries as you asked, you will need to use a condition group and to query the delta.

$query = \Drupal::entityQuery('node');
$query->condition('status', NODE_PUBLISHED)
  ->condition('type', 'custom_type')
  ->condition('custom_taxonomy', [2, 8], 'IN')
  ->condition('custom_taxonomy.%delta', 2, '=')
  ->sort('field_last_name', DESC);
$or = $query->orConditionGroup();
$or->condition('custom_taxonomy.0.target_id', 2);
$or->condition('custom_taxonomy.0.target_id', 8);
$query->condition($or);

See QueryInterface::condition documentation.

8
  • 1
    I implemented the answer, but for some reason it's not displaying the proper results. If I use only one of the $and conditions, like [2], 'IN' or [8], 'IN' it displays the results just fine, but when I use both, I don't get any results. I triple checked to make sure I have nodes that have both.
    – Amy
    Commented Jan 23, 2017 at 20:12
  • 1
    Thinking about it, there is no need for the AND conditionGroup because the entityQuery uses AND by default.
    – Eyal
    Commented Jan 23, 2017 at 20:14
  • 1
    Okay I changed it to just using $query->condition() but I'm still having the issue that when using both it doesn't display any results.
    – Amy
    Commented Jan 23, 2017 at 20:18
  • 1
    As per the QueryInterface::condition documentation you can apply conditions on the delta. I'll update the answer with an example code.
    – Eyal
    Commented Jan 23, 2017 at 20:19
  • 1
    @Eyal, the AND condition group seems to be redundant, but it really helps to specify multiple conditions for the same field. You only need to put each condition in a separate AND group.
    – 4uk4
    Commented Jan 23, 2017 at 20:34
1
$taxonomy_term = 'taxonomy_term';
    $vid = 'name_taxon';
    $terms = $this->entity_type_manager->getStorage($taxonomy_term)
      ->loadTree($vid);

foreach ($terms as $term) {
  $term_data[] = [
    "vid" => $term->vid,
    "name" => $term->name,
  ];
}
1

Drupal 9 looks like this

$userStorage = $this->entityTypeManager->getStorage('user');

$userQuery = $userStorage->getQuery();
$result_user_ids = $userQuery->accessCheck(FALSE)
  ->condition('field_user_nodes.target_id', [1,2,4], 'IN')
  ->condition('status', 1)
  ->execute();
// Above ^^ 
return $userStorage->loadMultiple($result_user_ids);
1
  • 1
    Are you sure this is correct? I tested it with D9.3 and the result is the same as described by the post owner. @4k4 's solution still works though.
    – theuni
    Commented Jan 27, 2022 at 10:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.