Model data collections and references
Query records that have no public page and connect documents with stable authored references.
Use a data collection for records such as authors, team members, and products that do not need their own pages.
import { defineCollection, defineContentConfig } from '@lupinum/ginko-content/config'
import { z } from 'zod'
export const team = defineCollection({
type: 'data',
source: 'team/*.yml',
schema: z.object({
name: z.string(),
role: z.string(),
order: z.number(),
avatar: z.string().optional()
})
})
export default defineContentConfig({ collections: { team } })ref: team:jane
name: Jane Doe
role: Documentation engineer
order: 1
avatar: /images/team/jane.jpgEvery record is queryable. A type: 'data' collection has no public routes and stays out of the sitemap.
Render records from a page
Query the collection with many, then render the results from an application page:
<script setup lang="ts">
import { many } from '@lupinum/ginko-content/client'
import { team } from '~~/content.config'
const { data: members } = await useAsyncData('team', () =>
many(team, {
sort: { order: 'asc' },
select: ['name', 'role', 'order', 'avatar']
})
)
</script>
<template>
<ul>
<li v-for="member in members" :key="member.canonicalKey">
<img v-if="member.avatar" :src="member.avatar" alt="">
<strong>{{ member.name }}</strong>
<span>{{ member.role }}</span>
</li>
</ul>
</template>Choose a source format
- YAML for compact, hand-authored records.
- JSON for machine-generated data.
- CSV for flat tables with stable columns.
- Markdown when a record needs a body.
Every format passes through the collection schema before a query can return it.
Link documents with refs
Give each target a ref, then declare the relation with reference(). The ref is the stable, authored value stored by other documents.
import { defineCollection, defineContentConfig, reference } from '@lupinum/ginko-content/config'
import { z } from 'zod'
export const authors = defineCollection({
type: 'data',
source: 'authors/*.yml',
schema: z.object({
name: z.string(),
bio: z.string().optional()
})
})
export const posts = defineCollection({
type: 'page',
source: 'blog/*.md',
route: '/blog',
schema: z.object({
title: z.string(),
author: reference('authors'),
related: z.array(reference('posts')).default([])
})
})
export default defineContentConfig({ collections: { authors, posts } })---
title: First post
ref: post:first
author: author:jane
related:
- post:second
---Store refs, not canonical keys. Ginko derivescanonicalKeyfrom content identity, so renaming or moving files can change it. An authoredrefstays stable until you choose to change it.
Populate a relation
Pass the target collection in populate to load the linked author with the post:
const post = await one(posts, {
by: { ref: 'post:first' },
populate: {
author: authors
}
})Populate only the relations the view renders.
Find documents that point back
Use backlinks to reverse the relation and load every post that names an author:
const authoredPosts = await backlinks(authors, {
by: { ref: 'author:jane' },
from: posts,
sort: { title: 'asc' }
})