Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Querying collections

A defined collection is read with functions from the astro:content module. getCollection() returns all entries, getEntry() returns one by its id, and render() turns the text of an entry into a component you can put on a page.

A list of posts

Open src/pages/posts/index.astro and replace the made-up cards with real posts:

---
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import PostCard from '../../components/PostCard.astro';
 
const posts = await getCollection('blog');
---
 
<BaseLayout title="Posts">
  <h1>Posts</h1>
  {posts.map((post) => (
    <PostCard title={post.data.title} url={`/posts/${post.id}`} />
  ))}
</BaseLayout>

Open /posts and there is a card for each file in src/content/blog. In the frontmatter you can use await directly, without wrapping it in an async function.

What an entry holds

FieldValue for first-post.md
post.idfirst-post, the file name without the extension
post.dataThe frontmatter checked by the schema: title, pubDate, tags
post.bodyThe raw Markdown text of the post
post.collectionblog

post.data.pubDate is already a Date object because the schema converted the string to a date.

Filtering and sorting

getCollection() takes a filter function as its second argument. Let us hide drafts and sort posts from newest to oldest:

---
import { getCollection } from 'astro:content';
 
const posts = (await getCollection('blog', ({ data }) => !data.draft))
  .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---

Posts with draft: true in the frontmatter disappear from the list, and the newest post comes first. Sorting is the ordinary array method sort(): Astro does not guarantee the order of entries.

One entry and its text

getEntry() finds an entry by collection name and id, and render() returns a Content component with the post's HTML. Create src/pages/posts/first-post.astro:

---
import { getEntry, render } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
 
const post = await getEntry('blog', 'first-post');
if (!post) throw new Error('Post not found');
 
const { Content } = await render(post);
---
 
<BaseLayout title={post.data.title}>
  <h1>{post.data.title}</h1>
  <Content />
</BaseLayout>

Open /posts/first-post and you see the heading and the post text converted from Markdown to HTML. You will not need such a file for every post: the next lesson replaces it with a single dynamic page.

Common mistake

People write post.title instead of post.data.title and get an empty spot on the page. Everything set in the frontmatter is in post.data, while the entry itself holds service fields such as id. The editor suggests the right path when Astro's types are set up.

Thanks for reading!

Donate to the site — we work hard for you.