Next.js Discord

Discord Forum

Making database queries from server components

Answered
Polar bear posted this in #help-forum
Open in Discord
Polar bearOP
Is it allowed to make a database queries from a server components that is not a page, or not.
because I get an error when I try to do so.
the error:
Module not found: Can't resolve 'dns'
  1 | 'use strict'
  2 |
> 3 | var dns = require('dns')
    |           ^^^^^^^^^^^^^^
  4 |
  5 | var defaults = require('./defaults')
  6 |

https://nextjs.org/docs/messages/module-not-found
Answered by Polar bear
this maybe because I'm making the components organised in a folders, and each folder have entry index.ts which exports everything from the folder together, like:
export * from './cards';
export * from './header';
export * from './navbar';
export * from './reusables';
export * from './theme-toggle';
export * from './filters';
export * from './tables';
export * from './forms';
export * from './featured';
export * from './footer';
View full answer

16 Replies

Polar bearOP
the parent:

import {
  BasePostCard,
  Pagination,
  PostCard,
  SearchInput,
} from '@/components';
import { Group, SimpleGrid, Stack, Text, Title } from '@mantine/core';
import { query } from './query';
import { CharacterFilter } from '@/components/filters/character';

type Props = {
  params: Promise<{ collectionId: string }>;
  searchParams: Promise<{
    page?: string;
    surah?: string;
    verse?: string;
    q?: string;
  }>;
};

const Collection = async ({ params, searchParams }: Props) => {
  const collectionId = +(await params).collectionId;
  const page = Number((await searchParams)?.page) || 1;
  const surah = (await searchParams).surah ?? '';
  const verse = (await searchParams).verse ?? '';
  const q = (await searchParams).q ?? '';

  const { collection, posts } = await query({
    collectionId,
    page,
    surah,
    verse,
    q,
  });

  console.log('we received ', collection);

  if (!posts.data.length) {
    return (
      <Stack>
        <Title>{collection.title}</Title>
        <Text>{collection.description}</Text>
        <p>no posts found</p>
      </Stack>
    );
  }

  return (
    <Stack>
      <Title>{collection.title}</Title>
      <Text>{collection.description}</Text>
      <Group justify='end' align='start'>
        <SearchInput />
        <CharacterFilter />
        {/* {resolveCollectionFilters(collection.extension)} */}
      </Group>
      <SimpleGrid
        cols={{
          base: 1,
          sm: 2,
          md: 3,
        }}
      >
        {posts?.type === 'BASE' &&
          posts.data.map((p) => <BasePostCard post={p} key={p.id} />)}
        {posts?.type !== 'BASE' &&
          posts.data.map((p) => (
            <PostCard
              key={p.id}
              post={{
                data: p,
                extension: posts.type,
              }}
            />
          ))}
      </SimpleGrid>
      <Pagination itemsCount={posts.count} />
    </Stack>
  );
};

export default Collection;
the child
import { db } from '@/db';
import { $postExtraData } from '@/db/schema';
import { eq } from 'drizzle-orm';

export const CharacterFilter = async () => {
  const characters = await db
    .select()
    .from($postExtraData)
    .where(eq($postExtraData.key, 'CHARACTER'));
  console.log('where the filter is living');
  return <p>hello</p>;
};
@joulev the code looks fine here, do you use this component in any other places? what happens if you add `import "server-only"` to the top of the component?
Polar bearOP
Ahh, I was doing this:

import { PostExtensionEnum } from '@/db/types';
import { SurahVerseFilters } from './surah-verse';
import { CharacterFilter } from './character';

export const resolveCollectionFilters = (extension: PostExtensionEnum) => {
  switch (extension) {
    case 'SURAH_WITH_VERSE':
      return <SurahVerseFilters />;
    case 'CHARACTER':
      return <CharacterFilter />;
  }
};

when I commented the code, the issue solved, thank you.
but why this is making an issue?
Polar bearOP
I'll try.
even this one still looks okay to me, not too sure what's wrong here. sure, a function is not the best idea here compared to a proper component but i don't see how that doesn't work either
Polar bearOP
same issue as if it is still a function.
this is not causing the problem:
import { PostExtensionEnum } from '@/db/types';
// import { SurahVerseFilters } from './surah-verse';
import { CharacterFilter } from './character';

export const ResolveCollectionFilters = ({
  extension,
}: {
  extension: PostExtensionEnum;
}) => {
  switch (extension) {
    case 'SURAH_WITH_VERSE':
      return <p>hi</p>;
    case 'CHARACTER':
      return <p>hiii</p>;
  }
};
this does cause an issue:
import { PostExtensionEnum } from '@/db/types';
// import { SurahVerseFilters } from './surah-verse';
import { CharacterFilter } from './character';

export const ResolveCollectionFilters = ({
  extension,
}: {
  extension: PostExtensionEnum;
}) => {
  switch (extension) {
    case 'SURAH_WITH_VERSE':
        return <SurahVerseFilters />;
    case 'CHARACTER':
        return <CharacterFilter /
  }
};
Polar bearOP
I think I know why this happens.
Polar bearOP
this maybe because I'm making the components organised in a folders, and each folder have entry index.ts which exports everything from the folder together, like:
export * from './cards';
export * from './header';
export * from './navbar';
export * from './reusables';
export * from './theme-toggle';
export * from './filters';
export * from './tables';
export * from './forms';
export * from './featured';
export * from './footer';
Answer
oh yeah then that is what it is. you are still (accidentally) importing the server component into a client component despite not using the server component there
so from the import chain, it will eventually be that you are importing "dns" (from the database connection) into a client component which doesn't work