#dynamic slug for getEntry

1 messages · Page 1 of 1 (latest)

silver obsidian
#

Hi,
How can I add a dynamic parameter when calling getEntry?

// Get src/content/blog/enterprise.md
const enterprisePost = await getEntry('blog', 'enterprise');

I want to access the slug of the blog entry, instead of hard-coding its name

for example: const enterprisePost = await getEntry('blog', enterprise.slug);

agile marlinBOT
#

Hi @silver obsidian. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To use a dynamic parameter when calling getEntry(), you can pass the slug as the second argument. However, it's important to note that getEntry() expects the id of the entry, not necessarily the slug. In many cases, the id is derived from the file name or path.

Here's how you can use a dynamic parameter with getEntry():

---
const { slug } = Astro.params;
const post = await getEntry('blog', slug);
---

This approach is typically used in dynamic route pages, such as [slug].astro.

However, if you're using custom slugs that differ from the file names, you'll need to use getCollection() first to find the entry with the matching slug, and then use getEntry() to fetch the full entry. Here's an example:

---
import { getCollection, getEntry } from 'astro:content';

const { slug } = Astro.params;

// First, get all blog entries
const allPosts = await getCollection('blog');

// Find the entry with the matching slug
const postEntry = allPosts.find(post => post.slug === slug);

// If found, get the full entry
const post = postEntry ? await getEntry(postEntry) : null;
---

This method allows you to use custom slugs while still leveraging the getEntry() function.

For more information on using getEntry() and working with dynamic routes in Astro, you can refer to the Content Collections API Reference and the Generating Routes from Content guide.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@silver obsidian Kapa.ai is still learning and improving, please let me know how I did by reacting below.

silver obsidian
#

@agile marlin

Sounds good.
can you help adjust my function

export async function getAllAuthorsData(
authors: CollectionEntry<"blog">["data"]["authors"],
): Promise<CollectionEntry<"authors">[]> {
const authorsData = authors.map(async (author:any) => {
const authorData = await getEntry("authors", slug);

if (authorData === undefined) {
  throw new Error(
    `Author "${author.slug}" not found in "authors" collection.`,
  );
}

return authorData;

});

// return a promise that is resolved when all promises in the array have been resolved
return Promise.all(authorsData);
}

agile marlinBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Based on the information provided in the knowledge sources, I can help you adjust your function to correctly use getEntry(). Here's an updated version of your function:

import { getEntry, type CollectionEntry } from 'astro:content';

export async function getAllAuthorsData(
  authors: CollectionEntry<"blog">["data"]["authors"]
): Promise<CollectionEntry<"authors">[]> {
  const authorsData = authors.map(async (author) => {
    const authorData = await getEntry("authors", author.id);

    if (authorData === undefined) {
      throw new Error(
        `Author with id "${author.id}" not found in "authors" collection.`,
      );
    }

    return authorData;
  });

  // return a promise that is resolved when all promises in the array have been resolved
  return Promise.all(authorsData);
}

Here are the key changes and explanations:

  1. We import getEntry and CollectionEntry from 'astro:content' at the top of the file.

  2. In the getEntry() call, we use author.id instead of slug. This is because getEntry() expects the id of the entry, not the slug. The id is typically derived from the file name or path of the content entry Content Collections API Reference.

  3. We've removed the :any type annotation from the author parameter in the map function. TypeScript should be able to infer the correct type based on the authors parameter type.

  4. In the error message, we now refer to the id instead of the slug.

This function assumes that the authors array in your blog entries contains objects with an id property that corresponds to the id of entries in the "authors" collection. If your data structure is different, you might need to adjust accordingly.

#

Remember that getEntry() is used to fetch a single entry from a collection. If you need to query multiple entries or use more complex filtering, you might want to consider using getCollection() instead Querying Collections.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@silver obsidian Kapa.ai is still learning and improving, please let me know how I did by reacting below.

wraith relic
#

@agile marlin It looks like my config isn't picking up files for my other collection. This is the config. ```import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const other = defineCollection({
loader: glob({ pattern: ['.mdx?', '!/**'], base: 'src/content' }),
schema: z.object({
title: z.string(),
accent: z.string(),
}),
});

const work = defineCollection({
loader: glob({ pattern: ['*.mdx?'], base: 'src/content/work' }),
schema: z.object({
title: z.string(),
date: z.date(),
accent: z.string(),
desc: z.string(),
project: z.string(),
roles: z.array(z.string()),
img: z.string()
}),
});

export const collections = { other, work };

agile marlinBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Based on the configuration you've provided, it seems that the issue might be with the glob pattern for your other collection. Let's analyze the configuration and suggest a possible solution.

For the other collection, you're using the following loader:

loader: glob({ pattern: ['*.mdx?', '!*/**'], base: 'src/content' }),

This pattern is looking for .md or .mdx files directly in the src/content directory, but not in any subdirectories. The !*/** part of the pattern explicitly excludes all subdirectories.

However, there might be a couple of issues:

  1. The ? in *.mdx? is making the x optional, so it would match both .md and .mdx files. If you want to match only .mdx files, you should remove the ?.

  2. The base directory is set to src/content, which means it's looking for files directly in this directory. Make sure your files are indeed located directly in src/content and not in a subdirectory.

To fix this, you could try adjusting the loader pattern like this:

const other = defineCollection({
    loader: glob({ pattern: '*.mdx', base: 'src/content' }),
    schema: z.object({
        title: z.string(),
        accent: z.string(),
    }),
});

This will look for all .mdx files directly in the src/content directory.

If your files are actually in a subdirectory of src/content, you should adjust the base and pattern accordingly. For example, if they're in src/content/other, you could use:

loader: glob({ pattern: '*.mdx', base: 'src/content/other' }),

If you're still having issues after making these changes, you might want to double-check:

  1. That your files exist in the correct location.
  2. That your files have the correct extension (.mdx in this case).
  3. That your files contain the required frontmatter fields (title and accent).
#

For more information on configuring content collections and using the glob loader, you can refer to the Defining Collections section of the Astro documentation.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: