Querying content

    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>
    }

    Getting a specific Entry

    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)

    Querying multiple Entries

    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)

    Limiting results

    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)

    Order results

    A result set can be ordered by passing one or multiple fields.

    const ordered = Query(NewsItem).orderBy(NewsItem.publishDate.desc())

    Group by

    Results can be grouped by one or more fields.

    const grouped = Query(NewsItem).groupBy(NewsItem.category)

    Creating queries

    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(...)

    Filtering by Field values

    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')
      )
    )

    Filtering by Entry values

    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')

    Selecting Fields

    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)
    })