GraphQL queries
GraphQL allows you to create queries in both shorthand and long-form formats.
To learn more about search queries:
To learn more about GraphQL query keywords:
- Total
- Where (Equal to, Not equal to, Contains)
- Order by
- Logical operators (AND, OR, AND with nested OR)
- Typename field
- GraphQL long-form queries
- Cursor based pagination (First, Page info, Has Next, End Cursor, After)
Search by ID
Search by ID returns a single result, the entity matching the ID.
In the following example, you search for the ID asset.alexander-mils-667996 on M.Asset, with the return fields of fileName, title, and createdon date:
{
m_Asset(id: "asset.alexander-mils-667996") {
fileName
title
createdOn
}
}
The results are as follows:
{
"data": {
"m_Asset": {
"fileName": "alexander-mils-667996.jpg",
"title": "Elderflower cordial",
"createdOn": "2021-02-02T00:34:47.000Z"
}
}
}
You can see immediately that the query has precisely the same shape as the result. This shape is essential to GraphQL because you always get back what you expect, and the server knows what fields you ask for. The fileName returns a string type, in this case, the name of the M.Asset entity with the asset.alexander-mils-667996 ID.
Search by definition
Search by definition returns a result set based on the entity searched.
In this example, you search all of M.Content (not for a single result) and request the return fields of id and content_Name:
{
allM_Content {
results {
id
content_Name
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"results": [
{
"id": "tTMVYivL2UyM3300lnraRQ",
"content_Name": "Fruitful Summer (gb)"
},
{
"id": "LB0MQmR3U0ST9NX2V4L_vA",
"content_Name": "Fruitful Summer (es)"
},
{
"id": "TmYSxnfrqUWL1-1VEL-ZdA",
"content_Name": "Fruitful Summer (us)"
},
{
"id": "Content.PowerofProtein",
"content_Name": "The Power of Protein"
},
{
"id": "Content.Snacking",
"content_Name": "Snacking"
},
{
"id": "Content.SalsaWithFruitChips",
"content_Name": "Flavorful's famous salsa with Healthful fruit chips"
}
]
}
}
}
Search by interface
Interfaces are an abstract type where there are common fields declared. Any type that implements an interface must define all the fields with exactly matching names and types. The implementations of interfaces are explicitly listed out in possible types.
In the following example, you search M.Content where the content name contains Fruitful Email, Fruitful Blog, or Healthy Mimosa.
The results include the content name field, the blog title and body fields from the virtual content blog type, and the email subject and body fields from the virtual email type. You make this inclusion by including the type appended with ... on [Type]
in the query, to create a sub-query:
query contentEmailBlogInterface {
allM_Content(
where: {
OR: [
{ content_Name_contains: "Fruitful Email" }
{ content_Name_contains: "Fruitful Blog" }
{ content_Name_contains: "Healthy Mimosa" }
]
}
) {
total
results {
content_Name
... on M_Content_Blog {
blog_Title
blog_Body
}
... on M_Content_Email {
email_Subject
email_Body
}
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 5,
"results": [
{
"content_Name": "Fruitful Blog",
"blog_Title": "Fruitful juices",
"blog_Body": "<figure class=\"image\"><img width=\"150\" alt=\"Fruitful logo (black)\" src=\"https://stylelabsdemo.com/api/public/content/363909544a354d3b9a4549c306c88bbe?v=ad464f64\"></figure><p><br> </p><p><i><strong>Un tonto se cree sabio, pero un hombre sabio sabe que es un tonto.</strong></i></p><figure class=\"image\"><img width=\"200\" alt=\"Fruitful Orange mocktail\" src=\"https://stylelabsdemo.com/api/public/content/0268acbebdb643aa83d918ff8d03283d?v=f3607a38\"></figure><p style=\"text-align:center;\"> </p><p style=\"text-align:center;\"> </p><p><i><strong>Más valen tres horas adelantadas que un minuto tarde.</strong></i></p>"
},
{
"content_Name": "Fruitful Email (es-ES)",
"email_Subject": "Fruitful juices",
"email_Body": "<figure class=\"image\"><img width=\"150\" alt=\"Fruitful logo (inverted)\" src=\"https://stylelabsdemo.com/api/public/content/5b2a9683096b4543b997346c15bda790?v=b426739c\"></figure><p><i><strong>Los cobardes mueren muchas veces antes de su muerte; los valientes nunca sienten la muerte sino sólo una vez</strong></i></p><figure class=\"image\"><img width=\"380\" alt=\"Lime mocktail with lime slice\" src=\"https://stylelabsdemo.com/api/public/content/99c986d065aa45fda3a692e0e27d3928?v=45b06955\"></figure><p><i><strong>El infierno está vacío y todos los demonios están aquí.</strong></i></p>"
},
{
"content_Name": "Fruitful Email",
"email_Subject": "Fruitful juices",
"email_Body": "<figure class=\"image\"><img width=\"150\" src=\"https://stylelabsdemo.com/api/public/content/5b2a9683096b4543b997346c15bda790?v=b426739c\" alt=\"Fruitful logo (inverted)\"></figure><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque non ipsum mattis, elementum velit maximus, mattis eros. </p><figure class=\"image\"><img srcset=\"https://stylelabsdemo.com/api/public/content/99c986d065aa45fda3a692e0e27d3928?v=45b06955&t=w320 320w\" width=\"380\" src=\"https://stylelabsdemo.com/api/public/content/99c986d065aa45fda3a692e0e27d3928?v=45b06955\" alt=\"Lime mocktail with lime slice\"></figure><p>Etiam cursus viverra ante eu faucibus. Ut porttitor.</p><p> </p>"
},
{
"content_Name": "Fruitful Blog",
"blog_Title": "Fruitful juices",
"blog_Body": "<figure class=\"image\"><img width=\"150\" src=\"https://stylelabsdemo.com/api/public/content/363909544a354d3b9a4549c306c88bbe?v=ad464f64\" alt=\"Fruitful logo (black)\"></figure><p><br> </p><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p><figure class=\"image\"><img width=\"200\" src=\"https://stylelabsdemo.com/api/public/content/0268acbebdb643aa83d918ff8d03283d?v=f3607a38\" alt=\"Fruitful Orange mocktail\"></figure><p style=\"text-align:center;\"> </p><p style=\"text-align:center;\"> </p><p> </p>"
},
{
"content_Name": "Healthy Mimosa blog",
"blog_Title": "Who wants a mimosa?!",
"blog_Body": "<p>I do, always! Mimosas are supremely simple bubbly cocktails made with sparkling wine and orange juice. They're light, fizzy and easy to sip.</p><p>I love ordering mimosas at weekend brunch, and serving them to family and friends on holidays—Easter, Mother's Day, July 4th, Christmas, you name it. Mimosas liven up wedding showers and baby showers. I bring mimosa supplies to football watch parties, and no one complains. I've shared a few variations on mimosas over the years. Today, I'm going to share everything you've ever wanted to know about mimosas, plus a basic mimosa recipe and variations. If you haven't poured your first mimosa yet, you'll be a mimosa expert by the end of this post! If you're a seasoned mimosa drinker, I think you'll find some new tips here, too.</p><p> </p><p><span class=\\\"text-big\\\"><strong>Mimosa Ingredients:</strong></span></p><p>Classic mimosas require just two ingredients: dry sparkling wine, and orange juice. Some recipes will tell you to add some other alcohol or orange liqueur. Don't listen to them!</p><p><strong>Sparkling Wine</strong></p><p>The best Champagne for mimosas isn't actually Champagne. For mimosas, opt for less-expensive Cava or Prosecco. Cava is from Spain and Prosecco is from Italy, but they're both delicious dry sparkling wines that mix well with juice. Bonus? They're affordable. A good bottle of Cava or Prosecco will run about $12 to $16. Avoid super cheap sparkling wine, unless you want a headache with your mimosas. Don't waste your pricy bottle of Champagne on mimosas, since we're diluting those delicate notes with orange juice.</p><p><strong>Orange Juice</strong></p><p>Cold, fresh orange juice is best for mimosas. If you're buying orange juice at the store, opt for high-quality such as the Fruitful Orange Juice!</p><p><strong>Mimosa Ratio</strong></p><p>The perfect ratio of sparkling wine to orange juice is up to you. My suggestion? Start with the 50/50 ratio suggested below and adjust from there. I make my mimosas with 2 parts sparkling wine and 1 part orange juice—they're light, fizzy, and pack a punch. That's how we made them when I was a bartender. If you like sweeter, more juicy mimosas, start with a 50/50 ratio and add more orange juice if desired. After some delicious experimentation, you'll know exactly how you like your mimosas!</p>"
}
]
}
}
}
Total
The total
function returns the number of entities that match specified criteria.
There are no criteria specified in the following example, so the query returns the total number of entities in M.Content:
{
allM_Content {
total
}
}
The results are as follows, with a total of 23 M.Content items:
{
"data": {
"allM_Content": {
"total": 23
}
}
}
Where
The where
clause restricts the number of results. You can use the where
condition in conjunction with logical operators such as AND and OR, and comparison operators such as:
Note
When using the AND logical operator, all the criteria must be met. When using the OR logical operator, any of the criteria can be met.
Equal to
In the following example, you use the _eq syntax where the title of M.Asset is equal to Group selfie with drinks:
query AssetTitle {
allM_Asset(where: { title_eq: "Group selfie with drinks" }) {
total
results {
fileName
fileSize
isDraft
}
}
}
The results are as follows:
{
"data": {
"allM_Asset": {
"total": 2,
"results": [
{
"fileName": "videoblock-example3.mp4",
"fileSize": 10.08,
"isDraft": true
},
{
"fileName": "videoblock-example3.mp4",
"fileSize": 10.08,
"isDraft": null
}
]
}
}
}
Not equal to
In the following example, you use the _neq syntax where isDraft is not equal to null:
query AssetDraftIsNotNull {
allM_Asset(where: { isDraft_neq: null }) {
total
results {
fileName
fileSize
isDraft
}
}
}
The results are as follows:
{
"data": {
"allM_Asset": {
"total": 1,
"results": [
{
"fileName": "videoblock-example3.mp4",
"fileSize": 10.08,
"isDraft": true
}
]
}
}
}
Contains
Use the contains
predicate in the WHERE
clause to perform a full-text search on full-text columns containing character-based data types. contains
searches for a word or a phrase.
In the following example, you search M.Content where the content name contains Fruitful:
{
allM_Content(where: { content_Name_contains: "Fruitful" }) {
total
results {
content_Name
m_Content_IsVariant
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 7,
"results": [
{
"content_Name": "Sparkling Punch using Fruitful Orange",
"m_Content_IsVariant": null
},
{
"content_Name": "Fruitful Summer (us)",
"m_Content_IsVariant": true
},
{
"content_Name": "Fruitful Summer (gb)",
"m_Content_IsVariant": true
},
{
"content_Name": "Fruitful Summer (es)",
"m_Content_IsVariant": null
},
{
"content_Name": "Fruitful refreshing ginger lemonade",
"m_Content_IsVariant": null
},
{
"content_Name": "Fruitful Cocktails",
"m_Content_IsVariant": null
},
{
"content_Name": "Fruitful Mocktails",
"m_Content_IsVariant": null
}
]
}
}
}
There are other parameters you can add here, for example:
[fieldname]_contains
: filters results where the string field contains a substring.[fieldname]_in
: checks a list to return records where the field's value matches any substring in a provided list.[fieldname]_starts_with
: an expression to check for values that start with a provided substring.[fieldname]_ends_with
: similar to the previous expression, only ending with a substring.
You can also add more to the list by using reverse statements (to return the opposite). For example: [fieldname]_not_contains
is the opposite of [fieldname]_contains
.
Order by
Use the orderBy
keyword to sort the result set in ascending or descending order.
In the following example, our query sorts results by the recipe title, in ascending order:
{
allM_Content_Recipe(
where: { recipe_Title_contains: "Fruitful" }
orderBy: RECIPE_TITLE_ASC
) {
total
results {
recipe_Title
}
}
}
The results are as follows:
{
"data": {
"allM_Content_Recipe": {
"total": 4,
"results": [
{
"recipe_Title": "Fruitful mango mocktail"
},
{
"recipe_Title": "Fruitful refreshing ginger lemonade as an alternative to soda"
},
{
"recipe_Title": "Fruitful's famous salsa with Healthful fruit chips"
},
{
"recipe_Title": "Sparkling Punch using Fruitful Orange"
}
]
}
}
}
Note
To sort in descending order, simply replace ASC with DESC.
Logical Operators
You can use filters wrapped in AND and OR logical operators.
AND
The AND operator displays a record if all the conditions separated by AND are TRUE.
In this example, the query returns results from M.Content where the content name contains Healthy Mimosa AND the the blog quote is equal to Who wants a mimosa:
{
allM_Content(
where: {
AND: [
{ content_Name_contains: "Healthy Mimosa" }
{ blog_Quote_neq: "Who wants a mimosa" }
]
}
) {
total
results {
content_Name
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 1,
"results": [
{
"content_Name": "Healthy Mimosa blog"
}
]
}
}
}
OR
The OR operator displays a record if any of the conditions separated by OR is TRUE. For example:
{
allM_Content(
where: {
OR: [
{ content_Name_contains: "The Power of Protein" }
{ content_Name_contains: "Healthy Mimosa" }
]
}
) {
total
results {
content_Name
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 2,
"results": [
{
"content_Name": "The Power of Protein"
},
{
"content_Name": "Healthy Mimosa blog"
}
]
}
}
}
AND with nested OR
You can nest the AND and OR operators.
The following query searches for content with a name equals Summer Savings, AND is not a variant that is either content with a name equal to Fruitful refreshing ginger lemonade OR was created on 2021-02-05T14:11:50.000Z:
{
allM_Content(
where: {
AND: [{ content_Name_eq: "Summer Savings" }
{ m_Content_IsVariant_eq: false }
]
OR: [
{ content_Name_eq: "Fruitful refreshing ginger lemonade" }
{ createdOn_eq: "2021-07-29T12:11:19.000Z" }
]
}
) {
total
results {
content_Name
m_Content_IsVariant
createdOn
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 3,
"results": [
{
"content_Name": "Summer Savings",
"m_Content_IsVariant": false,
"createdOn": "2021-07-29T13:56:32.000Z"
},
{
"content_Name": "Summer Savings",
"m_Content_IsVariant": false,
"createdOn": "2021-07-29T13:55:39.000Z"
},
{
"content_Name": "Fruitful refreshing ginger lemonade",
"m_Content_IsVariant": false,
"createdOn": "2021-07-29T12:17:38.000Z"
}
]
}
}
}
Typename
The __typename
field resolves to a string, which lets you differentiate between data types from the client. For example:
query typeName {
allM_Content(where: {content_Name_contains: "Mimosa"}) {
total
results{
content_Name
__typename
}
}
}
GraphQL long-form queries
You can begin this query with the syntax [your_query_name]
. You can name your query anything you want.
Within that query, you can perform multiple individual queries which you also give display names. The structure looks like the following:
query [your_query_name] {
[subquery_name]: [model_name](where: {[your_criteria]}){
[desired_field_name_1]
[desired_field_name_2]
[desired_field_name_3]
}
}
In the following example, there are two queries running at the same time:
The first query, named blog, searches M.Content, using the virtual blog types, for blogs containing Fruitful in the title, and which body is not null. You also order the results by the blog title, in ascending order.
The second query, named email, searches M.Content, using the virtual email types, for emails containing Fruitful in the title, and which body is not null. You also order the results by email type, in ascending order.
query contentEmailBlog {
blog: allM_Content_Blog(
where: { blog_Title_contains: "Fruitful", blog_Body_neq: null }
orderBy: BLOG_TITLE_ASC
) {
total
results {
blog_Title
blog_Body
blog_Quote
}
}
email: allM_Content_Email(
where: { email_Subject_contains: "Fruitful", email_Body_neq: null }
orderBy: EMAIL_SUBJECT_ASC
) {
total
results {
email_Subject
email_Body
}
}
}
The results are as follows (results are grouped):
{
"data": {
"blog": {
"total": 3,
"results": [
{
"blog_Title": "Fruitful blog",
"blog_Body": "<p>There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain. There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain. There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain</p><figure class=\"image\"><img width=\"1100\" alt=\"Refreshing mocktails\" src=\"https://stylelabsdemo.com/api/public/content/2ed85585609c43bda24ae92372a5f311?v=f4d87d58\"></figure>",
"blog_Quote": "<p>The <strong>fruit</strong> of your own hard work is the sweetest.</p>"
},
{
"blog_Title": "Fruitful blog",
"blog_Body": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi pulvinar tellus non augue vestibulum vulputate. Proin non tortor vitae ante tincidunt dictum eget vitae tortor.</p><figure class=\"image\"><img width=\"1100\" alt=\"Refreshing mocktails\" src=\"https://stylelabsdemo.com/api/public/content/2ed85585609c43bda24ae92372a5f311?v=f4d87d58\"></figure>",
"blog_Quote": "<p><br>Le fruit de votre propre travail acharné est le plus doux.</p>"
},
{
"blog_Title": "Fruitful blog",
"blog_Body": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi pulvinar tellus non augue vestibulum vulputate. Proin non tortor vitae ante tincidunt dictum eget vitae tortor.</p><figure class=\"image\"><img width=\"1100\" alt=\"Refreshing mocktails\" src=\"https://stylelabsdemo.com/api/public/content/2ed85585609c43bda24ae92372a5f311?v=f4d87d58\"></figure>",
"blog_Quote": "<p><br>El fruto de tu propio trabajo duro es el más dulce.</p>"
}
]
},
"email": {
"total": 1,
"results": [
{
"email_Subject": "Fruitful Late Summer Email",
"email_Body": "<p><br><strong>Fruitful: </strong></p><p>No hay nadie que ame el dolor mismo, que lo busque y quiera tenerlo, simplemente porque es dolor.</p><figure class=\"image\"><img width=\"1100\" alt=\"Product layer 3\" src=\"https://stylelabsdemo.com/api/public/content/c8cc3c37df854f9c92c0ddef0795198d?v=0039f433\"></figure>"
}
]
}
}
}
Cursor-based pagination
Cursor-based pagination works by returning a pointer to a specific item in the dataset. On subsequent requests, the server returns results after the given pointer. Cursor-based pagination addresses the drawbacks of using offset pagination but does so by making trade-offs:
- The cursor must be based on a unique, sequential column (or columns) in the source table.
- The client can not jump to a specific page.
First
The first
parameter limits the number of results returned by the query, for example, limit to 2. The returned results must be less than 1000. When first
argument is not provided, the default value of 10 is used. Queries return 10 results.
query firstTwo {
allM_Content(first:2) {
total
results {
id
content_Name
m_Content_IsVariant
}
}
}
The results are as follows: the total of results is 28, but only the first two results are returned:
{
"data": {
"allM_Content": {
"total": 28,
"results": [
{
"id": "BDolxU3bGkWMwFJk-s8Idg",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
},
{
"id": "igADXjecyk2oF4lo_tfs2Q",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
}
]
}
}
}
pageInfo
The pageInfo
field includes relevant information that is needed for the pagination. It returns a PageInfo type that is non-nullable.
endCursor
endCursor
represents the cursor associated with the last edge that is returned for the current query.
query endCursor {
allM_Content(first: 5) {
total
results {
id
content_Name
m_Content_IsVariant
}
pageInfo {
endCursor
hasNext
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 28,
"results": [
{
"id": "BDolxU3bGkWMwFJk-s8Idg",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
},
{
"id": "igADXjecyk2oF4lo_tfs2Q",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
},
{
"id": "p70lTBrPSkqTZ2Ky3BdmWw",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
},
{
"id": "9zjJfWK_UkSoX8Gd1I8dPg",
"content_Name": "Fruitful Summer",
"m_Content_IsVariant": null
},
{
"id": "OwuHPqtSNk25OF6CPz6s8A",
"content_Name": "Fruitful Juices",
"m_Content_IsVariant": null
}
],
"pageInfo": {
"endCursor": "eyJzZWFyY2hBZnRlciI6WyIxNjEzNzMyMDk1MTcyIl0sImNvdW50Ijo1fQ==",
"hasNext": true
}
}
}
}
hasNext
hasNext
is a Boolean value indicating if there are more results available:
query hasNext {
allM_Content(first: 2) {
total
results {
id
content_Name
m_Content_IsVariant
}
pageInfo {
hasNext
}
}
}
The results are as follows: hasNext
is true
, so there are more results that are not returned:
{
"data": {
"allM_Content": {
"total": 28,
"results": [
{
"id": "BDolxU3bGkWMwFJk-s8Idg",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
},
{
"id": "igADXjecyk2oF4lo_tfs2Q",
"content_Name": "Fruitful Summer (es-ES)",
"m_Content_IsVariant": true
}
],
"pageInfo": {
"hasNext": true
}
}
}
}
After
Pagination is done with the after
argument. You give it an endCursor
value from the previous query, and query the server for the results after that cursor:
query afterEndCursor {
allM_Content(
first: 5
after: "eyJzZWFyY2hBZnRlciI6WyIxNjEzNzMyMDk1MTcyIl0sImNvdW50Ijo1fQ=="
) {
total
results {
id
content_Name
m_Content_IsVariant
}
pageInfo {
endCursor
hasNext
}
}
}
The results are as follows:
{
"data": {
"allM_Content": {
"total": 28,
"results": [
{
"id": "wT5RNeIcQ0SHTORNT1faug",
"content_Name": "Fruitful Summer (it-IT)",
"m_Content_IsVariant": true
},
{
"id": "Content.SalsaWithFruitChips",
"content_Name": "Flavorful's famous salsa with Healthful fruit chips",
"m_Content_IsVariant": null
},
{
"id": "Content.PowerofProtein",
"content_Name": "The Power of Protein",
"m_Content_IsVariant": null
},
{
"id": "Content.PowerFromWithin",
"content_Name": "Power comes from within",
"m_Content_IsVariant": null
},
{
"id": "Content.FruitfulGinger",
"content_Name": "Fruitful refreshing ginger lemonade",
"m_Content_IsVariant": null
}
],
"pageInfo": {
"endCursor": "eyJzZWFyY2hBZnRlciI6WyIxNjEzMzY0Nzg0MTk4Il0sImNvdW50IjoxMH0=",
"hasNext": true
}
}
}
}
Can we improve this article ? Provide feedback