How to favor exact matches in entity reference autocomplete? Right now if you use entity reference autocomplete for short titles of a node type or entity type, and you have many items, due to the fact that by default they are ordered by entity id (nid), less relevant entries show up before exact matches.

For example, if you create a content type for stock symbols, and you have tens of thousands of them, and you want to search for "EA" or "DIS", longer strings that contain these substrings show up before exact matches.

How can you change the behavior so exact matches show up before other matches with lower entity ids?
Here's a way to alter the query for entity reference autocomplete. You can add an expression that returns the string length and then sorts by this.  This way, if a string contains "DIS", and it sorts by the string length, it will start with 3, and the only item that contains the string and is of the shortest length that contains the string (3) is the exact match, so it will show your exact match first, and then other relevant items that contain the string.  For example "ADIS" or "DISV".

/**
 * Implements hook_query_TAG_alter().
 *
 * Favor exact matches and shorter matches in node reference
 * autocomplete.
 */
function mymodule_query_entity_query_node_alter(AlterableInterface $query) {
  $routeMatch = \Drupal::routeMatch();

  if ($routeMatch-&gt;getRouteName() != 'system.entity_autocomplete' ||
    $routeMatch-&gt;getParameter('selection_handler') != 'default:node' ||
    $query-&gt;getMetaData('entity_type') != 'node') {
    return;
  }

  if (is_object($query-&gt;getMetaData('entity_reference_selection_handler')) &amp;&amp; $query-&gt;getMetaData('entity_type') == 'node') {
    $tables = $query-&gt;getTables();
    if (!empty($tables['node_field_data'])) {
      $query-&gt;addExpression('CHAR_LENGTH(node_field_data.title)', 'shortest');
      if ($groups = $query-&gt;getGroupBy()) {
        $query-&gt;groupBy('shortest');
      }
      $query-&gt;orderBy('shortest');
    }
  }
}

//You can use the same basic template for other entity types:

/**
 * Implements hook_query_TAG_alter().
 *
 * Favor exact matches and shorter matches in mycustomentity entity reference
 * autocomplete.
 */
function mymyodule_query_entity_query_mycustomentity_alter(AlterableInterface $query) {
  $routeMatch = \Drupal::routeMatch();

  if ($routeMatch-&gt;getRouteName() != 'system.entity_autocomplete' ||
    $routeMatch-&gt;getParameter('selection_handler') != 'default:mycustomentity' ||
    $query-&gt;getMetaData('entity_type') != 'mycustomentity') {
    return;
  }

  if (is_object($query-&gt;getMetaData('entity_reference_selection_handler')) &amp;&amp; $query-&gt;getMetaData('entity_type') == 'mycustomentity') {
    $tables = $query-&gt;getTables();
    if (!empty($tables['mycustomentity_field_data'])) {
      $query-&gt;addExpression('CHAR_LENGTH(mycustomentity_field_data.title)', 'shortest');
      if ($groups = $query-&gt;getGroupBy()) {
        $query-&gt;groupBy('shortest');
      }
      $query-&gt;orderBy('shortest');
    }
  }
}