Once content has been saved in the CMS you'll want a way to retrieve it. Your CMS instance has methods to fetch specific Entries or search through all content.
Content can be queried within React server components (and functions that run on the server such as generateStaticParams).
import {cms} from '@/cms'
import {Query} from 'alinea'
export default async function HomePage() {
const homePage = await cms.get(Query(HomePage))
return <h1>{homePage.title}</h1>
}
A single Entry can be fetched using the get method.
import {Query} from 'alinea'
const query = Query(HomePage).whereId(homePageId)
const entry = await cms.get(query)
Multiple Entries can be fetched using the find method.
import {Query} from 'alinea'
const query = Query(BlogPost).whereParent(blogId)
const blogPosts = await cms.find(query)
A result set can be limited using skip and take.
// Skip the first 10 entries and return a maximum of 10
const query = Query(BlogPost).skip(10).take(10)
A result set can be ordered by passing one or multiple fields.
const ordered = Query(NewsItem).orderBy(NewsItem.publishDate.desc())
Results can be grouped by one or more fields.
const grouped = Query(NewsItem).groupBy(NewsItem.category)
Results can be filtered using the where function, or tailored functions such as whereId or whereLocale. To find Entries of any Type, use the Query functions directly.
// Any entry that matches your conditions
const searchAllEntries = Query.where(...)
If you're looking for Entries of a specific Type, pass it to the Query function to create a query of that Type. This will correctly infer the result TypeScript type.
// Only entries of type BlogPost will be found
const narrowByType = Query(BlogPost).where(...)
To search Entries by specific Fields use the where function. Fields can be compared to values using its conditional methods.
// If filtered by Type first it's possible to match fields
// on equality directly by passing an object. This does not
// work for any other comparison operator.
const withPath = Query(BlogPost).where({path: 'why-you-should-get-a-cat'})
// Comparisons can be made by using the conditional methods
// of the field you're comparing to.
const recent = Query(BlogPost).where(
BlogPost.publishedDate.isGreaterOrEqual(`2024-01-01`)
)
// Multiple conditions result in matching on both (AND).
const previousYear = Query(BlogPost).where(
BlogPost.publishedDate.isGreaterOrEqual(`2023-01-01`),
BlogPost.publishedDate.isLess(`2024-01-01`)
)
// To match any condition use Query.or (OR).
const isPetPost = Query(BlogPost).where(
Query.or(
BlogPost.tags.includes('cats'),
BlogPost.tags.includes('dogs')
)
)
Entries contain values managed by the CMS such as an id, parent, the assigned workspace, root or locale. Query has shortcuts to query these directly.
const german = Query.whereLocale('de')
const blogPosts = Query(BlogPost).whereParent(blog.id)
// Multiple conditions can be chained
const secretPages = Query(Secret).whereWorkspace('secret').whereRoot('pages')
Entries can be queried with search terms. Any (Rich) Text Field with the searchable option set to true is indexed.
// Search can be used in combination with conditions
const containsDogs = Query(BlogPost).where(...).search('dog')
// Multiple search terms can be used
const containsBothDogsAndCats = Query(BlogPost).search('cat', 'dog')
Resulting rows can be narrowed to contain only specific fields.
// Returns a select set of fields
const rows = Query(BlogPost).select({
// Entry fields are available on Query
id: Query.id,
url: Query.url,
title: BlogPost.title,
description: BlogPost.shortDescription
})
// You can include all available Entry fields at once
const rows = Query(BlogPost).select({
...Query.entry,
title: BlogPost.title,
description: BlogPost.shortDescription
})
Entries in Alinea are part of a content tree. This means they'll often have a parent Entry or contain children Entries. To query content from the parent(s) or children you can request it within the selection.
// Select a few fields from the parent Entries to render
// a breadcrumb navigation.
const breadcrumbs = Query.parents().select({
url: Query.url,
title: Query.title
})
// Use it directly in another select
const blogPosts = Query(BlogPost).select({
// Select the fields you want from this blog post
title: BlogPost.title,
body: BlogPost.body,
// ... and include the data of the parents
breadcrumbs
})
// You can use the spread operator to make the above more readable
const blogPosts = Query(BlogPost).select({
// Select all fields of the BlogPost type
...BlogPost,
breadcrumbs
})
// Similarly you can fetch parent and children in one query
const blog = Query(Blog).select({
title: Blog.title,
posts: Query.children(BlogPost)
})