HomeDev guideAPI Reference
Dev guideUser GuideLegal TermsGitHubNuGetDev CommunitySubmit a ticketLog In

Recursive queries

Describe how to use recursive queries in Optimizely Graph.

In content management systems (CMSs), content items are often linked or nested within one another. For example, a landing page might contain various content blocks, each containing other nested elements. Optimizely Graph provides mechanisms to traverse these relationships efficiently.

Self-recurring queries (@recursive directive solution)

The @recursive directive lets you recursively extend your query with the specified depth while traversing nested relationships. Using the GraphQL client to communicate Optimizely Graph is a limited but safer option.

The following example shows the recursive directive:

query recursiveQuery {  
  _Content(limit: 100, where: { _metadata: { types: { eq: "StartPage" } } }) {  
    items {  
      ... on StartPage {  
        TestAreas {  
          ...LandingPage  
        }  
      }  
    }  
  }  
}

fragment LandingPage on _IContent {  
  _metadata {  
    displayName  
    types  
  }  
  ... on GroupCardListBlock {  
    GroupedItemContentArea @recursive(depth: 10)  
  }  
  ... on LandingPage {  
    TopContentArea @recursive(depth: 2)  
    MainContentArea @recursive  
  }  
}

Explanation

  • Entry Point – The query starts by fetching StartPage content items. The TestAreas is typed of ContentArea to contain nested content items.
  • Fragment – The LandingPage fragment defines the data structure you want to retrieve from each content item.

@recursive directive

  • GroupedItemContentArea @recursive(depth: 10) – This instructs Optimizely GraphQL to fetch nested content within GroupedItemContentArea up to a depth of ten levels. The allowed depth is between one and ten.

    • TopContentArea @recursive(depth: 2) – Similar to the above, but limited to two levels of nesting.

    • MainContentArea @recursive – This has no specified depth, meaning it will fetch all nested content within MainContentArea by one level (this is the default value).

    • The @recursive directive must be applied to a field that returns the same type as its associated fragment. For example, content areas like GroupedItemContentArea, TopContentArea, and MainContentArea are suitable for the @recursive directive because they all return _IContent. You can verify this by checking the Documentation Explorer on GraphiQL.

Key Points

  • Flexibility – You can control the recursion depth for different fields.
  • Efficiency – Recursive queries can be more efficient than multiple round trips to fetch nested data.
  • Cycle Prevention – The depth argument prevents infinite loops.

Circular-referenced queries (cyclic fragments)

Circular-referenced queries are a much more natural way to retrieve data for the nested blocks. You can reuse the fragment definitions as either self (A -> A) or cross (A -> B -> C -> A) referenced way to retrieve the nested data.

The following example shows a cyclic query:

query cyclicQuery {  
  _Content(limit: 100, where: { _metadata: { types: { eq: "StartPage" } } }) {  
    items {  
      ... on StartPage {  
        TestAreas {  
          ...LandingPage  
        }  
      }  
    }  
  }  
}

fragment LandingPage on _IContent {  
  _metadata {  
    displayName  
    types  
  }  
  ... on GroupCardListBlock {  
    GroupedItemContentArea {  
      ...LandingPage  
    }  
  }  
  ... on LandingPage {  
    TopContentArea {  
      ...LandingPage  
    }  
    MainContentArea {  
      ...LandingPage  
    }  
  }  
}

Explanation

  • This query and fragment are identical to the recursive query.
  • The difference is that the LandingPage fragment reference in the query does not have any depth info, so it might be infinitely deep in theory. But it is not because it depends on the indexed data, which has ten levels of depth.
  • The lines of ...LandingPage must be placed under the fields that are in the same data type with its associated fragment, which is _IContent in this case. Here, it is correctly placed inside GroupedItemContentArea, TopContentArea, and MainContentArea, all of which return _IContent, similar to the placement requirements for the @recursive directive.

Important Considerations

Performance – Be mindful of the performance implications, especially when dealing with deeply nested content.
Compliance – Although using a cyclic query is a much easier and more flexible method, it may not be compatible with your GraphQL client.