HomeDev guideAPI ReferenceGraphQL
Dev guideUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket

Joins with linking

How to create joins on items within and across content types.

Items are instances of content types. It is possible to join items from the same or other content types within or across sources in a single Optimizely Graph query by linking them with different connection types. This is powerful because it makes it possible to query your content as a graph, although still represented as a hierarchy due to the nature of GraphQL. The advantages of using joins with linking include:

  • A single GraphQL query to create joins within and between content types and get a single response, which is much faster and more efficient than building/parsing multiple queries/responses yourself
  • Flexibility to establish connections within your data models, add more semantics to the data modeling, and support automated linking in the Optimizely Graph query language
  • Filtering and search capabilities are still supported when doing a "linked" query

The system allows linking based on properties (fields) of an item. The property of the item that you want to link from needs to be specified, as well as the property of an item that you want to link to. Optimizely Graph allows you to create joins on any field to any field, where the field must be the outer node, i.e., the node that directly contains a value, so you cannot link to nodes that are a composition. A link is established if there is a common value between both properties.

Configuration in the Content Types

You can configure links in the Content Types definitions on the root level, similar to languages and contentTypes with the property links. The links property is optional. The system allows you to specify multiple link types and allows you to define these types with a key like this:

"links": {
    "DEFAULT": {
      "from": "Tags",
      "to": "ContentLink.GuidValue"
    },
    "AUTHOR": {
      "from": "MetaKeywords___searchable",
      "to": "Tags"
    },
    "knows-of": {
      "from": "Tags",
      "to": "Tags"
    },
    "friend": {
      "from": "FriendOf",
      "to": "Name___searchable"
    }
}

Optimizely recommends that you always set the DEFAULT link type, since Optimizely will use this in case the type is not specified. The values of the properties need to be specified as JSON path.

  • from – the property that should be the origin of the link
  • to – the property that should be the destination of the link

The properties can be multi-valued, so be of type array. In case you have not specified the DEFAULT, then the linking will work the same as the Parent/child queries. The GraphQL schema is created by using the keys specified in the Content Types definition, but we create enums by converting the keys to uppercase and replace hyphens with underscore. In case of duplicate keys, the system will use the first one only. So in the example above, we will create the following link type enums: DEFAULT, AUTHOR, KNOWS_OF, FRIEND.

Query with _link

There is a special field _link to do the joins on the properties configured. It must be specified as a field within items. It can consist of an optional input argument called type that accepts LinkTypes enum values. These enum values are created based on the keys specified by you in the Content Types definitions.

📘

Note

  • The system does not impose any restrictions on the content types, so you can do joins on a query from any content type to any content type.
  • A link is established if there is at least 1 common value between the to and from, and the common value is defined by you.
  • We restrict the nesting of _link by a depth of 3, so you cannot create joins deeper than this level.

Here is a basic example of a query, where we create a join between instances of StartPage and BiographyPage.

{
  StartPage {
    items {
      MetaKeywords
      _link {
        BiographyPage {
          items {
            Name
            Tags
          }
        }
      }
    }
  }
}

Examples

Assume we have the above link types defined in our Content Types definitions. Then we could create the following queries to query with this configuration.

If we would query without specifying any link type, it will use the DEFAULT link type like this query, where it will join items from StandardPage within BiographyPage.

{
  BiographyPage {
    items {
      Name
      Tags
      _link {
        StandardPage(where: { ContentLink: { GuidValue: { exist: true } } }) {
          items {
            Name
            _fulltext
            ContentLink {
              GuidValue
            }
          }
        }
      }
    }
  }
}

The response would look like this. Note that we created links between the items in the Tags field with values reference1 and reference2.

{
  "data": {
    "BiographyPage": {
      "items": [
        {
          "Name": "Arnold Schwarzenegger",
          "Tags": [],
          "_link": {
            "StandardPage": null
          }
        },
        {
          "Name": "Alan Turing",
          "Tags": [
            "reference1",
            "reference2"
          ],
          "_link": {
            "StandardPage": {
              "items": [
                {
                  "Name": "Standard Page 12",
                  "_fulltext": [
                    "Wild Wild West is a 1999 American steampunk Western film co-produced and directed by Barry Sonnenfeld and written by S. S. Wilson and Brent Maddock alongside Jeffrey Price and Peter S. Seaman, from a story penned by brothers Jim and John Thomas. Loosely adapted from The Wild Wild West, a 1960s television series created by Michael Garrison, it is the only production since the television film More Wild Wild West (1980) to feature the characters from the original series. The film stars Will Smith (who previously collaborated with Sonnenfeld on Men in Black two years earlier in 1997) and Kevin Kline as two U.S. Secret Service agents who work together to protect U.S. President Ulysses S. Grant (Kline, in a dual role) and the United States from all manner of dangerous threats during the American Old West.",
                    "Standard Page 12"
                  ],
                  "ContentLink": {
                    "GuidValue": "reference2"
                  },
                  "__typename": "StandardPage"
                },
                {
                  "Name": "Standard Page 13",
                  "_fulltext": [
                    "chi nhánh Cần Thơ",
                    "Standard Page 13"
                  ],
                  "ContentLink": {
                    "GuidValue": "reference1"
                  },
                  "__typename": "StandardPage"
                }
              ]
            }
          }
        },
        {
          "Name": "Marie Curie",
          "Tags": [
            "reference2"
          ],
          "_link": {
            "StandardPage": {
              "items": [
                {
                  "Name": "Standard Page 12",
                  "_fulltext": [
                    "Wild Wild West is a 1999 American steampunk Western film co-produced and directed by Barry Sonnenfeld and written by S. S. Wilson and Brent Maddock alongside Jeffrey Price and Peter S. Seaman, from a story penned by brothers Jim and John Thomas. Loosely adapted from The Wild Wild West, a 1960s television series created by Michael Garrison, it is the only production since the television film More Wild Wild West (1980) to feature the characters from the original series. The film stars Will Smith (who previously collaborated with Sonnenfeld on Men in Black two years earlier in 1997) and Kevin Kline as two U.S. Secret Service agents who work together to protect U.S. President Ulysses S. Grant (Kline, in a dual role) and the United States from all manner of dangerous threats during the American Old West.",
                    "Standard Page 12"
                  ],
                  "ContentLink": {
                    "GuidValue": "reference2"
                  },
                  "__typename": "StandardPage"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

You could even define social networks within your data as the following query shows with the FRIEND link type. Note that is a purely fictional example.

{
  BiographyPage {
    items {
      Name
      FriendOf
      _link(type: FRIEND) {
        BiographyPage {
          items {
            Name
          }
        }
      }
    }
  }
}

And here is the response, where we see that Allan Turing is friends with Marie Curie, and vice versa. The other persons do not have a linked friend.

{
  "data": {
    "BiographyPage": {
      "items": [
        {
          "Name": "Arnold Schwarzenegger",
          "FriendOf": [],
          "_link": {
            "BiographyPage": null
          }
        },
        {
          "Name": "Alan Turing",
          "FriendOf": [
            "Marie Curie"
          ],
          "_link": {
            "BiographyPage": {
              "items": [
                {
                  "Name": "Marie Curie"
                }
              ]
            }
          }
        },
        {
          "Name": "Marie Curie",
          "FriendOf": [
            "Alan Turing"
          ],
          "_link": {
            "BiographyPage": {
              "items": [
                {
                  "Name": "Alan Turing"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

The joins are very flexible, allowing you even to create circular joins as the following example with KNOWS_OF shows, which links from/to the same field. However, note that we restrict the depth of _link usage to 3.

{
  BiographyPage {
    items {
      Name
      Tags
      _link(type: KNOWS_OF) {
        BiographyPage {
          items {
            Name
            Tags
            __typename
          }
        }
      }
    }
  }
}

This is how the response could look like:

{
  "data": {
    "BiographyPage": {
      "items": [
        {
          "Name": "Arnold Schwarzenegger",
          "Tags": [],
          "_link": {
            "BiographyPage": null
          }
        },
        {
          "Name": "Alan Turing",
          "Tags": [
            "reference1",
            "reference2"
          ],
          "_link": {
            "BiographyPage": {
              "items": [
                {
                  "Name": "Alan Turing",
                  "Tags": [
                    "reference1",
                    "reference2"
                  ],
                  "__typename": "BiographyPage"
                },
                {
                  "Name": "Marie Curie",
                  "Tags": [
                    "reference2"
                  ],
                  "__typename": "BiographyPage"
                }
              ]
            }
          }
        },
        {
          "Name": "Marie Curie",
          "Tags": [
            "reference2"
          ],
          "_link": {
            "BiographyPage": {
              "items": [
                {
                  "Name": "Alan Turing",
                  "Tags": [
                    "reference1",
                    "reference2"
                  ],
                  "__typename": "BiographyPage"
                },
                {
                  "Name": "Marie Curie",
                  "Tags": [
                    "reference2"
                  ],
                  "__typename": "BiographyPage"
                }
              ]
            }
          }
        }
      ]
    }
  }
}

There is an extra way, that you can add two link types into one query, as a solution to join three tables with different key-pairs as the following example shows:

{
      BiographyPage {
        items {
          Name
          Tags
          LinkWithDefaultType: _link {
            StandardPage {
              items {
                Name
                ContentLink {
                  GuidValue
                }
              }
            }
          }
          LinkWithSpecificType: _link(type: KNOWS_OF) {
            BiographyPage {
              items {
                Name
                Tags
              }
            }
          }
        }
      }
    }

This is how the response could look like:

{
  "data": {
    "data": {
      "BiographyPage": {
        "items": [
          {
            "LinkWithDefaultType": {
              "StandardPage": {
                "items": [
                  {
                    "ContentLink": {
                      "GuidValue": "test",
                    },
                    "Name": "Page title2",
                  },
                ],
              },
            },
            "LinkWithSpecificType": {
              "BiographyPage": {
                "items": [
                  {
                    "Name": "Arnold Schwarzenegger",
                    "Tags": [
                      "test",
                    ],
                  },
                  {
                    "Name": "Alan Turing",
                    "Tags": [
                      "reference1",
                      "reference2",
                      "test",
                    ],
                  },
                ],
              },
            },
            "Name": "Arnold Schwarzenegger",
            "Tags": [
              "test",
            ],
          },
          {
            "LinkWithDefaultType": {
              "StandardPage": {
                "items": [
                  {
                    "ContentLink": {
                      "GuidValue": "reference2",
                    },
                    "Name": "Standard Page 12",
                  },
                  {
                    "ContentLink": {
                      "GuidValue": "reference1",
                    },
                    "Name": "Standard Page 13",
                  },
                  {
                    "ContentLink": {
                      "GuidValue": "test",
                    },
                    "Name": "Page title2",
                  },
                ],
              },
            },
            "LinkWithSpecificType": {
              "BiographyPage": {
                "items": [
                  {
                    "Name": "Arnold Schwarzenegger",
                    "Tags": [
                      "test",
                    ],
                  },
                  {
                    "Name": "Alan Turing",
                    "Tags": [
                      "reference1",
                      "reference2",
                      "test",
                    ],
                  },
                  {
                    "Name": "Marie Curie",
                    "Tags": [
                      "reference2",
                    ],
                  },
                ],
              },
            },
            "Name": "Alan Turing",
            "Tags": [
              "reference1",
              "reference2",
              "test",
            ],
          },
          {
            "LinkWithDefaultType": {
              "StandardPage": {
                "items": [
                  {
                    "ContentLink": {
                      "GuidValue": "reference2",
                    },
                    "Name": "Standard Page 12",
                  },
                ],
              },
            },
            "LinkWithSpecificType": {
              "BiographyPage": {
                "items": [
                  {
                    "Name": "Alan Turing",
                    "Tags": [
                      "reference1",
                      "reference2",
                      "test",
                    ],
                  },
                  {
                    "Name": "Marie Curie",
                    "Tags": [
                      "reference2",
                    ],
                  },
                ],
              },
            },
            "Name": "Marie Curie",
            "Tags": [
              "reference2",
            ],
          },
        ],
      },
    },
}