Что такое getCollection() и как он используется с Content Collections API?
getCollection('name') возвращает типизированный массив всех записей коллекции из src/content/, где схема frontmatter определена через defineCollection и Zod в src/content/config.ts. Поддерживает фильтрацию, связи между коллекциями и render() для Markdown.
getCollection() и Content Collections API
getCollection() — функция из модуля astro:content, которая загружает все записи из именованной коллекции контента. Content Collections API — система типобезопасной работы с локальным контентом (Markdown, MDX, JSON, YAML) в Astro.
Определение коллекции
Коллекции определяются в файле src/content/config.ts с помощью функций defineCollection и z (Zod-схема для валидации frontmatter).
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blogCollection = defineCollection({
type: 'content', // 'content' для Markdown/MDX, 'data' для JSON/YAML
schema: z.object({
title: z.string(),
pubDate: z.date(),
description: z.string(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
author: z.string().optional(),
}),
});
const authorsCollection = defineCollection({
type: 'data',
schema: z.object({
name: z.string(),
email: z.string().email(),
avatar: z.string().url().optional(),
}),
});
export const collections = {
blog: blogCollection,
authors: authorsCollection,
};
Структура файлов
Контент хранится в папках src/content/<collection-name>/:
src/content/
blog/
first-post.md
second-post.mdx
nested/
deep-post.md
authors/
john.json
jane.yaml
Использование getCollection()
Функция возвращает массив Entry-объектов. Каждый объект содержит: id, slug, body (для Markdown), data (типизированные данные frontmatter), collection.
---
// src/pages/blog/index.astro
import { getCollection, getEntry } from 'astro:content';
// Получить все записи коллекции
const allPosts = await getCollection('blog');
// Фильтрация: убрать черновики в production
const publishedPosts = await getCollection('blog', ({ data }) => {
return import.meta.env.PROD ? !data.draft : true;
});
// Сортировка по дате
const sortedPosts = publishedPosts.sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
// Получить одну запись по ID
const featured = await getEntry('blog', 'first-post');
// Рендер Markdown/MDX в HTML
const { Content } = await featured.render();
---
<ul>
{sortedPosts.map((post) => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString('ru-RU')}
</time>
</li>
))}
</ul>
Использование в getStaticPaths()
Типичный паттерн — генерация статических страниц для каждой записи коллекции:
---
// src/pages/blog/[...slug].astro
import { getCollection } from 'astro:content';
import type { CollectionEntry } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
interface Props {
post: CollectionEntry<'blog'>;
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
Связи между коллекциями
Можно ссылаться на записи другой коллекции через reference() в схеме:
// src/content/config.ts
import { defineCollection, reference, z } from 'astro:content';
const blogCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
author: reference('authors'), // ссылка на коллекцию authors
relatedPosts: z.array(reference('blog')).optional(),
}),
});
// Разрешение ссылки
import { getEntry } from 'astro:content';
const post = await getEntry('blog', 'first-post');
const author = await getEntry(post.data.author); // автоматически типизировано
Подводные камни
getCollection()кешируется в рамках одного build-запуска, но в SSR каждый запрос читает файлы заново — для высоконагруженных SSR-сайтов это может быть медленным, нужен внешний кеш.- Поле
slugгенерируется из пути к файлу относительно папки коллекции — вложенные папки создают slug видаnested/deep-post, что может сломать URL-паттерны, если это не учесть. - Тип
'content'поддерживаетrender(), тип'data'— нет. Путаница между ними приводит к ошибке TypeScript. - Zod-схема валидирует frontmatter при сборке — ошибки валидации блокируют всю сборку, а не только конкретную страницу.
z.date()в Zod парсит строки формата ISO 8601, но не все форматы дат в Markdown frontmatter — лучше явно указывать2024-01-15без времени и timezone.- Фильтр-функция в
getCollection('blog', filter)применяется после загрузки всех файлов — нет ленивой загрузки, все файлы читаются всегда. - MDX-файлы требуют установки
@astrojs/mdxинтеграции — без неё.mdxфайлы в коллекции игнорируются без предупреждения.
Common mistakes
- Звать
getCollectionв клиентском коде острова. - Полагаться на
entry.slugв новых коллекциях Astro 5. - Ожидать «живых» обновлений от коллекций без ребилда.
What the interviewer is testing
- Различает
getCollection,getEntry,getEntries. - Помнит, что функция серверная и работает с кешем.
- Знает связь с
getStaticPathsиrender().