I have two content types lets say A and B. B has a entity reference field which references A. Now I can have multiple contents of type B that references the same content of type A. I have a views that lists fields of Content type A and I have used relationship to show some fields of B which references that particular row. But it shows duplicate entries which is obvious due to the left join. I was wondering is there any way in which I can only show rows of A's fields and B's field in which the B is the latest one. i.e. If there are two instances of B which references A then in the view only show rows in which the values of the one where B is the latest one.

If anyone has done this or has idea on how to do it, i would much appreciate it.

Thanks in advance.

Comments

SilviaT’s picture

Trying to do the same here. Haven't found a solution yet.

nikita_tt’s picture

https://stackoverflow.com/a/2111420/8018195 This helped me with this issue.

Below is copy/paste of the stackoverflow answer (just in case):

This is an example of the greatest-n-per-group problem that has appeared regularly on StackOverflow.

Here's how I usually recommend solving it:

SELECT c.*, p1.*
FROM customer c
JOIN purchase p1 ON (c.id = p1.customer_id)
LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND 
    (p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
WHERE p2.id IS NULL;

Explanation: given a row p1, there should be no row p2 with the same customer and a later date (or in the case of ties, a later id). When we find that to be true, then p1 is the most recent purchase for that customer.

Regarding indexes, I'd create a compound index in purchase over the columns (customer_id, date, id). That may allow the outer join to be done using a covering index. Be sure to test on your platform, because optimization is implementation-dependent. Use the features of your RDBMS to analyze the optimization plan. E.g. EXPLAIN on MySQL.


Useful comment:
If you want to include customers who never made a purchase, then change JOIN purchase p1 ON (c.id = p1.customer_id) to LEFT JOIN purchase p1 ON (c.id = p1.customer_id)


How this helped me (Drupal 8):
I created custom Relationship views plugin:

<?php

namespace Drupal\MYMODULENAME\Plugin\views\relationship;

use Drupal\views\Plugin\views\relationship\EntityReverse;
use Drupal\views\Views;

/**
 * Makes a relation to the first or latest referencing entity.
 *
 * @ingroup views_relationship_handlers
 *
 * @link https://www.drupal.org/project/entityreference/issues/1941488
 * @link https://stackoverflow.com/a/2111420/8018195
 *
 * @ViewsRelationship("order_based_entity_reverse")
 */
class OrderBasedEntityReverse extends EntityReverse {

  /**
   * {@inheritdoc}
   *
   * @var \Drupal\views\Plugin\views\query\Sql
   */
  public $query = NULL;

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['comparasion_operator'] = ['default' => '<'];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);

    // @todo - add conditions for this case.
    $form['required']['#disabled'] = TRUE;

    $form['comparasion_operator'] = [
      '#title' => $this->t('Choose which referencing entity you want to connect'),
      '#type' => 'radios',
      '#required' => TRUE,
      '#default_value' => $this->options['comparasion_operator'],
      '#options' => [
        '<' => $this->t('Latest Referencing'),
        '>' => $this->t('First Referencing'),
      ],
    ];
  }

  /**
   * Called to implement a relationship in a query.
   */
  public function query() {
    parent::query();
    // @todo - does it need to have an ability to change this on the plugin form?
    $compare_field = 'entity_id';

    // First, relate our base table to the current base table to the
    // field, using the base table's id field to the field's column.
    $views_data = Views::viewsData()->get($this->table);
    $left_field = $views_data['table']['base']['field'];
    $third = [
      'left_table' => $this->tableAlias,
      'left_field' => $left_field,
      'table' => $this->definition['field table'],
      'field' => $this->definition['field field'],
      'adjusted' => TRUE,
      'type' => 'LEFT OUTER',
      'compare_with_table' => $this->first_alias,
      'compare_field' => $compare_field,
      'comparison_operator' => $this->options['comparasion_operator'],
    ];

    $third_join = $this->joinManager->createInstance('order_based_entity_reverse_join', $third);
    $third_join->adjusted = TRUE;

    $alias = $this->tableAlias . '_' . $left_field;
    $this->third_alias = $this->query->addRelationship($alias, $third_join, $this->definition['base'], $this->relationship);
    $this->query->addWhere(100, "{$this->third_alias}.{$compare_field}", NULL, 'IS NULL');
  }

}

And created the Join view plugin (it is used in the custom Relationship plugin; see "order_based_entity_reverse_join").

<?php

namespace Drupal\MYMODULENAME\Plugin\views\join;

use Drupal\views\Plugin\views\join\JoinPluginBase;

/**
 * Default implementation of the join plugin.
 *
 * @ingroup views_join_handlers
 *
 * @ViewsJoin("order_based_entity_reverse_join")
 */
class OrderBasedEntityReverseJoin extends JoinPluginBase {

  /**
   * {@inheritdoc}
   */
  public function buildJoin($select_query, $table, $view_query) {
    // Add an additional hardcoded condition to the query.
    $this->extra = "{$this->configuration['compare_with_table']}.{$this->configuration['compare_field']} {$this->configuration['comparison_operator']} {$table['alias']}.{$this->configuration['compare_field']}";
    parent::buildJoin($select_query, $table, $view_query);
  }

}

This custom relationship plugin has to be added to the entity reference field (which references to A) in the entity type B.