Answers.Body: <p>Currently, it can't be done out of the box, since it's currently not possible to search the related entries like this.</p>
  <p>However, you can extend GraphQL to pull this off. Ideally, it would be possible to add arguments to existing queries, but that won't be possible until Craft 4.0, so you'll have to add an entirely new query.</p>
  <p>So, add a custom query and register it. It should in essence be an almost facsimile of <code>craft\gql\queries\Entry</code>, with the addition of an additional argument. Let's pretend you named it <code>searchRelated</code>.</p>
  <p>Now also create an argument handler and register it. You would set the <code>$argumentName</code> value to match the name you picked above and your <code>handleArgument</code> method would do the search and return the matching element ids in the form of <code>[[$ids]]</code>. The double-array is required because the method is expected to return a list of id sets for more complex matches (for example, <code>relatedAssets: [{criteriaSet1}, {criteriaSet2}]</code>). This is not relevant to your specific case, however, it does enforce a certain syntax that has to be adhered to.</p>
  <p>Anyway, if all is done correctly, you should be able to use your new query to fetch the results you want.</p>
  <p>Some relevant reading on extending GraphQL:</p>
  <ul>
  <li><a href="https://craftcms.com/docs/3.x/extend/graphql.html#queries" rel="nofollow noreferrer">https://craftcms.com/docs/3.x/extend/graphql.html#queries</a></li>
  <li><a href="https://craftcms.com/docs/3.x/extend/graphql.html#example-argument-handler-class" rel="nofollow noreferrer">https://craftcms.com/docs/3.x/extend/graphql.html#example-argument-handler-class</a></li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-25T18:31:08.250Z
Answers.Text: Thank you so much - this will be very helpful! Question: So I don't actually need a custom resolver for this? Just a custom argument handler?
Answers.UserDisplayName: Eric
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-26T06:31:02.903Z
Answers.Text: Just a custom argument handler. The ids you return (provided you extend the `RelationArgumentHandler` class) are going to get included in the `relatedTo` argument.
  
  So, run your search based on the argument value. That will get you entry ids. Since Craft doesn't have the concept of reverse relations, you'll have to do another search to find the Matrix Blocks that are related to the entries with the ids you have.
  
  After that, you should return the ids of all the Matrix Blocks and, as they get rolled in the `relatedTo` argument, you get a list of the entries related to the Matrix Blocks.
Answers.UserDisplayName: Andris Sevcenko
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-26T18:11:01.553Z
Answers.Text: That makes sense, I feel like I am close. I have the entry IDs being returned based on my search:
  
  nestedEntries(searchRelated: [{search: "*out*"}]) { ... }
  
  I'm not sure where to look to find the function for the subsequent query though. Can you point me in the direction of where I can find the query that will allow me to "find the Matrix Blocks that are related to the entries with the ids you have"?
Answers.UserDisplayName: Eric
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-27T11:43:02.350Z
Answers.Text: Something like `$relatedIds = MatrixBlock::find()->select('ownerId')->column();` should return what you're after. (`MatrixBlock` should be an alias of `\craft\elements\MatrixBlock`).
Answers.UserDisplayName: Andris Sevcenko
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-27T18:43:13.383Z
Answers.Text: Thank you so much for your help thus far Andris, I added the line you mentioned and I am getting back another set of IDs, however, no results appear as a result of the query. I added the relevant code to the original question for posterity and also for a complete look at how to accomplish this. Something still isn't right and I'm not sure what it is. One thing I had to add that you didn't mention is a custom argument class, not sure if that's causing the issue although I can't imagine it would. Thoughts?
Answers.UserDisplayName: Eric
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-30T08:59:06.047Z
Answers.Text: My apologies. I had both over-analyzed and under-analyzed what the argument handler should accomplish here. 
  
  It still extends the base relational argument handler class, since we want the built-in capability of resolving nested relational arguments there, but the `handleArgument` method already returns the specific element `ids` we're after.
  
  I rewrote the class to fit the purpose and tested it. You can find it here: I rewrote that one file here: https://gist.github.com/andris-sevcenko/2245ca93e8adc91a3752a82d5b345050
Answers.UserDisplayName: Andris Sevcenko
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-31T14:14:37.060Z
Answers.Text: No worries at all - those code as you provided works perfectly. I cannot thank you enough! I plan on publishing this as a plugin on the Craft CMS store so others can make use of it as well!
Answers.UserDisplayName: Eric
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-08-25T13:58:07.403Z
Answers.LastActivityDate: 2021-08-25T13:58:07.403Z
Answers.UserDisplayName: Andris Sevcenko
Body: <p>So I have a fairly complex section structure that (on an Entry Type) has a matrix field that contains entries as fields(sub-entry) within a blocktype.</p>
  <p>I'd like to write a GraphQL query such that when text is matched on a field in the sub-entry on the matrix blocktype to return the entire section entry. I have thus far only been able to return matches on the title of the sub-entry. When I search for text on a custom field within the sub-entry nothing is returned. I <em>do</em> have the <code>Use this field’s values as search keywords</code> option checked on the matrix field of the main entry, and the custom fields on the sub-entry checked as well. I also went poking around the database in the <code>searchindex</code> table and I can see the field values/keywords in there for the sub-entry I created.</p>
  <p>Here is the query I've been playing around with:</p>
  <pre><code>fragment tour on tours_tour_Entry {
    title
    ... on tours_tour_Entry {
      title
      tourVariety
      duration
      complexity
      thumbnail {
        url
      }
      backgroundImage {
        url
      }
      introHeading
      introSubheading
      introContentBlocks {
        ... on introContentBlocks_introBlock_BlockType {
          body
        }
      }
      factsHeading
      factsContentBlocks {
        ... on factsContentBlocks_factsContentBlock_BlockType {
          body
        }
      }
      tourPois {
        ... on tourPois_tourPoi_BlockType {
          title
          description
          poi {
            title
            ... on pois_poi_Entry {
              fov
              description
              astroObjects {
                ... on astroObjects_astroObject_Entry {
                  ra
                  dec
                  image {
                    url
                  }
                  characteristics
                }
              }
            }
          }
        }
      }
    }
  }
  
  fragment poi on pois_poi_Entry {
    fov
    description
    astroObjects {
      ... on astroObjects_astroObject_Entry {
        ra
        dec
        image {
          url
        }
        characteristics
      }
    }
  }
  
  fragment astroObject on astroObjects_astroObject_Entry {
    ra
    dec
    image {
      url
    }
    characteristics
  }
  
  {
    entries(search: &quot;*desc* OR *char*&quot;) {
      ...tour
      ...poi
      ...astroObject
    }
  }
  </code></pre>
  <p>When I perform this search, the fragments for &quot;poi&quot; and &quot;astroObject&quot; return results, but not &quot;tour&quot;. What am I doing wrong in the query or in the &quot;tour&quot; fragment&quot;? Is this even possible?</p>
  <p><strong>Edit based on Andris's answer:</strong></p>
  <p>(Including all the relevant code for posterity)</p>
  <p>Okay, so I've created a custom plugin that extends the relevant classes and I'm still not able to get entries as results - which is odd considering that I am getting IDs back from my custom query.</p>
  <p>Plugin.php</p>
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  namespace edr;
  
  use Craft;
  use edr\queries\EntryAsField;
  use edr\arguments\EntryAsFieldArgumentHandler;
  use craft\events\RegisterGqlQueriesEvent;
  use craft\services\Gql;
  use yii\base\Event;
  use craft\gql\ArgumentManager;
  use craft\events\RegisterGqlArgumentHandlersEvent;
  
  class Plugin extends \craft\base\Plugin {
      public static $plugin;
  
      public $hasCpSettings = true;
  
      public function init() {
          parent::init();
          self::$plugin = $this;
  
          $this-&gt;registerArgumentHandler();
          $this-&gt;registerQuery();
          
      }
  
      protected function createSettingsModel() {
          return new \edr\models\Settings();
      }
  
      protected function registerArgumentHandler() {
          Event::on(
              ArgumentManager::class,
              ArgumentManager::EVENT_DEFINE_GQL_ARGUMENT_HANDLERS,
              function(RegisterGqlArgumentHandlersEvent $event) {
                  $event-&gt;handlers[&quot;searchRelated&quot;] = EntryAsFieldArgumentHandler::class;
              }
          );
      }
  
      protected function settingsHtml() {
          return \Craft::$app-&gt;getView()-&gt;renderTemplate(
              'edr-nested-entry-query/settings',
              [ 'settings' =&gt; $this-&gt;getSettings() ]
          );
      }
  
      public function registerQuery() {
          Event::on(
              Gql::class,
              Gql::EVENT_REGISTER_GQL_QUERIES,
              function(RegisterGqlQueriesEvent $event) {                
                  $event-&gt;queries['nestedEntries'] = EntryAsField::getQueries();
              }
          );
      }
  }
  </code></pre>
  <p>EntryAsField.php</p>
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  
  namespace edr\queries;
  
  use edr\arguments\EntryAsFieldArguments;
  use craft\gql\arguments\elements\Entry as EntryArguments;
  use craft\gql\base\Query;
  use craft\gql\interfaces\elements\Entry as EntryInterface;
  use craft\gql\resolvers\elements\Entry as EntryResolver;
  use craft\helpers\Gql as GqlHelper;
  use GraphQL\Type\Definition\Type;
  
  class EntryAsField extends \craft\gql\base\Query
  {
      public static function getQueries($checkToken = true): array
      {
          if ($checkToken &amp;&amp; !GqlHelper::canQueryEntries()) {
              Craft::info(&quot;platypus&quot;);
              return [];
          }
  
          return [
                  'type' =&gt; Type::listOf(EntryInterface::getType()),
                  'args' =&gt; EntryAsFieldArguments::getArguments(),
                  'resolve' =&gt; EntryResolver::class . '::resolve',
                  'description' =&gt; 'This query is used to query for entries.',
                  'complexity' =&gt; GqlHelper::relatedArgumentComplexity(),
          ];
      }
  }
  </code></pre>
  <p>EntryAsFieldArguments.php</p>
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  
  namespace edr\arguments;
  
  use GraphQL\Type\Definition\Type;
  use craft\gql\types\QueryArgument;
  use craft\gql\types\input\criteria\Entry;
  
  class EntryAsFieldArguments extends \craft\gql\base\ElementArguments
  {
      public static function getArguments(): array
      {
          return array_merge(parent::getArguments(), self::getContentArguments(), [
              'searchRelated' =&gt; [
                  'name' =&gt; 'searchRelated',
                  'type' =&gt; Type::listOf(Entry::getType()),
                  'description' =&gt; 'Matches search on entries-as-fields and returns the whole entry.'
              ],
          ]);
      }
  }
  </code></pre>
  <p>EntryAsFieldArgumentHandler.php</p>
  <pre class="lang-php prettyprint-override"><code>&lt;?php
  
  namespace edr\arguments;
  
  use Craft;
  use craft\elements\Entry;
  use craft\gql\base\RelationArgumentHandler;
  use craft\elements\MatrixBlock;
  
  class EntryAsFieldArgumentHandler extends RelationArgumentHandler
  {
      protected $argumentName = 'searchRelated';
  
      protected function handleArgument($argumentValue)
      {
          Craft::info(&quot;bobcat&quot;);
          $argumentValue = parent::handleArgument($argumentValue);
          $ids = $this-&gt;getIds(Entry::class, $argumentValue);
          $relatedIds = MatrixBlock::find()-&gt;select('ownerId')-&gt;column();
          if(count($relatedIds) &gt; 0) { // dedupe and stuff in 2d array
              $relatedIds = [array_unique($relatedIds)];
          }
          Craft::info(&quot;nested-entries-graphql-queries - DEBUG - Returned IDs from 1st query&quot;);
          Craft::info($ids);
          Craft::info(&quot;nested-entries-graphql-queries - DEBUG - Returned IDs from 2nd queryz&quot;);
          Craft::info($relatedIds);
          return $relatedIds;
      }
  }
  </code></pre>
  <p>In the argument handler above, the first query to getIDs() returns IDs fine. The MatrixBlock query to get the ownerIDs also returns IDs fine and I return these IDs as a 2d array. I get no results from this query though - am I missing something?</p>
  <p>Query:</p>
  <pre><code>{
    nestedEntries(searchRelated: [{search: &quot;*out*&quot;}]) {
      id
      title
    }
  }
  </code></pre>
  
Tags: <entries><entries-field><graphql><entry-query>
Title: How do I write a GraphQL query to search through sub-entries/entries as fields and return the whole entry?
ThreadText: # How do I write a GraphQL query to search through sub-entries/entries as fields and return the whole entry?
  
  (Asked by: username_0 on 2021-07-14)
  
  So I have a fairly complex section structure that (on an Entry Type) has a matrix field that contains entries as fields(sub-entry) within a blocktype.
  
  I'd like to write a GraphQL query such that when text is matched on a field in the sub-entry on the matrix blocktype to return the entire section entry. I have thus far only been able to return matches on the title of the sub-entry. When I search for text on a custom field within the sub-entry nothing is returned. I *do* have the `Use this field’s values as search keywords` option checked on the matrix field of the main entry, and the custom fields on the sub-entry checked as well. I also went poking around the database in the `searchindex` table and I can see the field values/keywords in there for the sub-entry I created.
  
  Here is the query I've been playing around with:
  
  ```
  fragment tour on tours_tour_Entry {
    title
    ... on tours_tour_Entry {
      title
      tourVariety
      duration
      complexity
      thumbnail {
        url
      }
      backgroundImage {
        url
      }
      introHeading
      introSubheading
      introContentBlocks {
        ... on introContentBlocks_introBlock_BlockType {
          body
        }
      }
      factsHeading
      factsContentBlocks {
        ... on factsContentBlocks_factsContentBlock_BlockType {
          body
        }
      }
      tourPois {
        ... on tourPois_tourPoi_BlockType {
          title
          description
          poi {
            title
            ... on pois_poi_Entry {
              fov
              description
              astroObjects {
                ... on astroObjects_astroObject_Entry {
                  ra
                  dec
                  image {
                    url
                  }
                  characteristics
                }
              }
            }
          }
        }
      }
    }
  }
  
  fragment poi on pois_poi_Entry {
    fov
    description
    astroObjects {
      ... on astroObjects_astroObject_Entry {
        ra
        dec
        image {
          url
        }
        characteristics
      }
    }
  }
  
  fragment astroObject on astroObjects_astroObject_Entry {
    ra
    dec
    image {
      url
    }
    characteristics
  }
  
  {
    entries(search: "*desc* OR *char*") {
      ...tour
      ...poi
      ...astroObject
    }
  }
  
  ```
  
  When I perform this search, the fragments for "poi" and "astroObject" return results, but not "tour". What am I doing wrong in the query or in the "tour" fragment"? Is this even possible?
  
  **Edit based on username_1's answer:**
  
  (Including all the relevant code for posterity)
  
  Okay, so I've created a custom plugin that extends the relevant classes and I'm still not able to get entries as results - which is odd considering that I am getting IDs back from my custom query.
  
  Plugin.php
  
  ```php
  <?php
  namespace edr;
  
  use Craft;
  use edr\queries\EntryAsField;
  use edr\arguments\EntryAsFieldArgumentHandler;
  use craft\events\RegisterGqlQueriesEvent;
  use craft\services\Gql;
  use yii\base\Event;
  use craft\gql\ArgumentManager;
  use craft\events\RegisterGqlArgumentHandlersEvent;
  
  class Plugin extends \craft\base\Plugin {
      public static $plugin;
  
      public $hasCpSettings = true;
  
      public function init() {
          parent::init();
          self::$plugin = $this;
  
          $this->registerArgumentHandler();
          $this->registerQuery();
          
      }
  
      protected function createSettingsModel() {
          return new \edr\models\Settings();
      }
  
      protected function registerArgumentHandler() {
          Event::on(
              ArgumentManager::class,
              ArgumentManager::EVENT_DEFINE_GQL_ARGUMENT_HANDLERS,
              function(RegisterGqlArgumentHandlersEvent $event) {
                  $event->handlers["searchRelated"] = EntryAsFieldArgumentHandler::class;
              }
          );
      }
  
      protected function settingsHtml() {
          return \Craft::$app->getView()->renderTemplate(
              'edr-nested-entry-query/settings',
              [ 'settings' => $this->getSettings() ]
          );
      }
  
      public function registerQuery() {
          Event::on(
              Gql::class,
              Gql::EVENT_REGISTER_GQL_QUERIES,
              function(RegisterGqlQueriesEvent $event) {                
                  $event->queries['nestedEntries'] = EntryAsField::getQueries();
              }
          );
      }
  }
  
  ```
  
  EntryAsField.php
  
  ```php
  <?php
  
  namespace edr\queries;
  
  use edr\arguments\EntryAsFieldArguments;
  use craft\gql\arguments\elements\Entry as EntryArguments;
  use craft\gql\base\Query;
  use craft\gql\interfaces\elements\Entry as EntryInterface;
  use craft\gql\resolvers\elements\Entry as EntryResolver;
  use craft\helpers\Gql as GqlHelper;
  use GraphQL\Type\Definition\Type;
  
  class EntryAsField extends \craft\gql\base\Query
  {
      public static function getQueries($checkToken = true): array
      {
          if ($checkToken && !GqlHelper::canQueryEntries()) {
              Craft::info("platypus");
              return [];
          }
  
          return [
                  'type' => Type::listOf(EntryInterface::getType()),
                  'args' => EntryAsFieldArguments::getArguments(),
                  'resolve' => EntryResolver::class . '::resolve',
                  'description' => 'This query is used to query for entries.',
                  'complexity' => GqlHelper::relatedArgumentComplexity(),
          ];
      }
  }
  
  ```
  
  EntryAsFieldArguments.php
  
  ```php
  <?php
  
  namespace edr\arguments;
  
  use GraphQL\Type\Definition\Type;
  use craft\gql\types\QueryArgument;
  use craft\gql\types\input\criteria\Entry;
  
  class EntryAsFieldArguments extends \craft\gql\base\ElementArguments
  {
      public static function getArguments(): array
      {
          return array_merge(parent::getArguments(), self::getContentArguments(), [
              'searchRelated' => [
                  'name' => 'searchRelated',
                  'type' => Type::listOf(Entry::getType()),
                  'description' => 'Matches search on entries-as-fields and returns the whole entry.'
              ],
          ]);
      }
  }
  
  ```
  
  EntryAsFieldArgumentHandler.php
  
  ```php
  <?php
  
  namespace edr\arguments;
  
  use Craft;
  use craft\elements\Entry;
  use craft\gql\base\RelationArgumentHandler;
  use craft\elements\MatrixBlock;
  
  class EntryAsFieldArgumentHandler extends RelationArgumentHandler
  {
      protected $argumentName = 'searchRelated';
  
      protected function handleArgument($argumentValue)
      {
          Craft::info("bobcat");
          $argumentValue = parent::handleArgument($argumentValue);
          $ids = $this->getIds(Entry::class, $argumentValue);
          $relatedIds = MatrixBlock::find()->select('ownerId')->column();
          if(count($relatedIds) > 0) { // dedupe and stuff in 2d array
              $relatedIds = [array_unique($relatedIds)];
          }
          Craft::info("nested-entries-graphql-queries - DEBUG - Returned IDs from 1st query");
          Craft::info($ids);
          Craft::info("nested-entries-graphql-queries - DEBUG - Returned IDs from 2nd queryz");
          Craft::info($relatedIds);
          return $relatedIds;
      }
  }
  
  ```
  
  In the argument handler above, the first query to getIDs() returns IDs fine. The MatrixBlock query to get the ownerIDs also returns IDs fine and I return these IDs as a 2d array. I get no results from this query though - am I missing something?
  
  Query:
  
  ```
  {
    nestedEntries(searchRelated: [{search: "*out*"}]) {
      id
      title
    }
  }
  
  ```
  
  **Tags:** entries, entries-field, graphql, entry-query
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2021-08-25. Score: 2 | Accepted answer
  
  Currently, it can't be done out of the box, since it's currently not possible to search the related entries like this.
  
  However, you can extend GraphQL to pull this off. Ideally, it would be possible to add arguments to existing queries, but that won't be possible until Craft 4.0, so you'll have to add an entirely new query.
  
  So, add a custom query and register it. It should in essence be an almost facsimile of `craft\gql\queries\Entry`, with the addition of an additional argument. Let's pretend you named it `searchRelated`.
  
  Now also create an argument handler and register it. You would set the `$argumentName` value to match the name you picked above and your `handleArgument` method would do the search and return the matching element ids in the form of `[[$ids]]`. The double-array is required because the method is expected to return a list of id sets for more complex matches (for example, `relatedAssets: [{criteriaSet1}, {criteriaSet2}]`). This is not relevant to your specific case, however, it does enforce a certain syntax that has to be adhered to.
  
  Anyway, if all is done correctly, you should be able to use your new query to fetch the results you want.
  
  Some relevant reading on extending GraphQL:
  
  * <https://craftcms.com/docs/3.x/extend/graphql.html#queries>
  * <https://craftcms.com/docs/3.x/extend/graphql.html#example-argument-handler-class>
  
  > **Comments:**
  > **username_0**: Thank you so much - this will be very helpful! Question: So I don't actually need a custom resolver for this? Just a custom argument handler?  
  > **username_1**: Just a custom argument handler. The ids you return (provided you extend the `RelationArgumentHandler` class) are going to get included in the `relatedTo` argument.  So, run your search based on the argument value. That will get you entry ids. Since Craft doesn't have the concept of reverse relations, you'll have to do another search to find the Matrix Blocks that are related to the entries with the ids you have.  After that, you should return the ids of all the Matrix Blocks and, as they get rolled in the `relatedTo` argument, you get a list of the entries related to the Matrix Blocks.  
  > **username_0**: That makes sense, I feel like I am close. I have the entry IDs being returned based on my search:  nestedEntries(searchRelated: [{search: "*out*"}]) { ... }  I'm not sure where to look to find the function for the subsequent query though. Can you point me in the direction of where I can find the query that will allow me to "find the Matrix Blocks that are related to the entries with the ids you have"?  
  > **username_1**: Something like `$relatedIds = MatrixBlock::find()->select('ownerId')->column();` should return what you're after. (`MatrixBlock` should be an alias of `\craft\elements\MatrixBlock`).  
  > **username_0**: Thank you so much for your help thus far username_1, I added the line you mentioned and I am getting back another set of IDs, however, no results appear as a result of the query. I added the relevant code to the original question for posterity and also for a complete look at how to accomplish this. Something still isn't right and I'm not sure what it is. One thing I had to add that you didn't mention is a custom argument class, not sure if that's causing the issue although I can't imagine it would. Thoughts?  
  > **username_1**: My apologies. I had both over-analyzed and under-analyzed what the argument handler should accomplish here.   It still extends the base relational argument handler class, since we want the built-in capability of resolving nested relational arguments there, but the `handleArgument` method already returns the specific element `ids` we're after.  I rewrote the class to fit the purpose and tested it. You can find it here: I rewrote that one file here: https://gist.github.com/username_1-username_1/2245ca93e8adc91a3752a82d5b345050  
  > **username_0**: No worries at all - those code as you provided works perfectly. I cannot thank you enough! I plan on publishing this as a plugin on the Craft CMS store so others can make use of it as well!  
  
  ---
  
  