0

I have an RSS feed display in a view, and one of the fields in the view is a multi-value taxonomy reference field. The feed settings have a "Grouping field" setting, and I've chosen that field (and I also have DISTINCT selected in the query settings), but I still get duplicate records.

When I run the query in MYSQL, I can see that it returns one record per term, so I'm guessing the grouping like that is handled in the display layer that an RSS view doesn't have (even though it does have a grouping setting).

That being said, what is a good place to filter out duplicate results? I saw the Views Distinct module, but it doesn't have a D8 release. In looking at the views hooks, it looks like hook_views_pre_render would be the best place, because at that point the query is run and the $view object has the results.

If anyone has experience with this or a better way, I'm open to suggestions.

Thanks.

3 Answers 3

2

Here's what I came up with that does the job:

/**
 * Implements hook_views_query_pre_render().
 */
function video_export_views_pre_render(Drupal\views\ViewExecutable $view) {
  $unique_nids = $new_results = array();

  // Loop through results and filter out duplicate results.
  foreach($view->result as $index => $result) {
    if(!in_array($result->nid, $unique_nids)) {
      $unique_nids[] = $result->nid;
    }
    else {
      $new_results[] = $result;
    }
  }
  // Replace $view->result with new array. Apparently views requires sequentially keyed
  // array of results instead of skipping keys (e.g. 0, 2, 4, etc), so we can't just
  // unset the duplicates.
  $view->result = $new_results;
}
1
  • The code in the else branch should go in the if statement; otherwise $result is added to $new_results when the node ID is already in the $unique_nids array. In other words, if there are 4 rows for the same node, the first row is not added to that array, but the other 3 rows are added.
    – apaderno
    Mar 28, 2019 at 9:04
2

@wonder95, this doesn't seem to work for me since there are 2 errors in your code IMHO.

First, you should be filling up the $new_results array inside your if condition and not the else condition.

Secondly, $view->result = $new_results; has no affect on the final result set. You'll need to use unset instead.

Below is my final working code

function hook_views_pre_render(\Drupal\views\ViewExecutable $view) {
   if ($view->id() == 'my_view') {
     $unique_nids = array();
     foreach($view->result as $key => $result) {
       if(!in_array($result->nid, $unique_nids)) {
         $unique_nids[] = $result->nid;
       }
       else {
         unset($view->result[$key]);
       }
     }
   }
 }
0

Extending @NKP's answer, there's another situation where you might run into this problem, and that's when you are using a taxonomy term view for some reason (in my case I need to start with a term), and you add the related content as a relationship, but still filter by term ID as contextual filter.

If a node is tagged with more than one term, it might produce duplicates. In this case, this variation of the hook worked for me, in case anyone else has the same problem:

function HOOK_views_pre_render(\Drupal\views\ViewExecutable $view) {
  $view_id = $view->id();

  if ($view_id == 'YOUR_VIEW_MACHINE_NAME') {
    $filter_tid = $view->args[0]; // supposing the TID is your first contextual filter

    $view->result = array_filter($view->result, function ($result) use ($filter_tid) {
      return $result->tid == $filter_tid; // keep only the nodes related to a term matching the contextual filter 
    });
  }
}

Your Answer

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

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