Next.js Discord

Discord Forum

SeacrhTerm

Answered
AmangLy posted this in #help-forum
Open in Discord
how to implement, i have create client-side and i need help for mongodb in serverside
// components/SearchForm.tsx

import { useSearchParams, usePathname, useRouter } from "next/navigation";
import { useDebouncedCallback } from "use-debounce";


export default function SearchForm() {
  const searchParams = useSearchParams();
  const pathname = usePathname();
  const { replace } = useRouter();

  const handleSearch = useDebouncedCallback((term) => {
    console.log(`Searching... ${term}`);
    const params = new URLSearchParams(searchParams);
    if (term) {
      params.set("query", term);
    } else {
      params.delete("query");
    }
    replace(`${pathname}?${params.toString()}`);
  }, 2000);

  return (
    <div className="bg-gray-100 rounded-lg mt-8 p-4">
      <form className="relative" onSubmit={(e) => e.preventDefault()}>
        {/* Input Field */}
        <input
          type="search"
          className="w-full bg-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-600"
          placeholder="Search Game"
          aria-label="Search game"
          onChange={(e) => {
            handleSearch(e.target.value);
          }}
          defaultValue={searchParams.get("query")?.toString()}
        />

        {/* Search Button */}
        <button type="submit" className="absolute right-0 bottom-2 mt-5 mr-4">
          <svg
            className="w-6 h-6 text-gray-800 dark:text-black"
            aria-hidden="true"
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 20 20"
          >
            <path
              stroke="currentColor"
              stroke-linecap="round"
              stroke-linejoin="round"
              stroke-width="2"
              d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
            />
          </svg>
        </button>
      </form>
    </div>
  );
}
Answered by AmangLy
export const getProducts = async (page: number = 1, pageSize: number = 10, search: string = "") => {
  const collection = (await getDB()).collection(COLLECTION_NAME);
  const skip = (page - 1) * pageSize;

  const query = search ? { name: { $regex: search, $options: "i" } } : {};

  const products = await collection.find(query)
    .skip(skip)
    .limit(pageSize)
    .toArray() as ProductModel[];

  return products;
};
View full answer

25 Replies

Sure, let me check the code
@AmangLy how to implement, i have create client-side and i need help for mongodb in serverside js // components/SearchForm.tsx import { useSearchParams, usePathname, useRouter } from "next/navigation"; import { useDebouncedCallback } from "use-debounce"; export default function SearchForm() { const searchParams = useSearchParams(); const pathname = usePathname(); const { replace } = useRouter(); const handleSearch = useDebouncedCallback((term) => { console.log(`Searching... ${term}`); const params = new URLSearchParams(searchParams); if (term) { params.set("query", term); } else { params.delete("query"); } replace(`${pathname}?${params.toString()}`); }, 2000); return ( <div className="bg-gray-100 rounded-lg mt-8 p-4"> <form className="relative" onSubmit={(e) => e.preventDefault()}> {/* Input Field */} <input type="search" className="w-full bg-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-600" placeholder="Search Game" aria-label="Search game" onChange={(e) => { handleSearch(e.target.value); }} defaultValue={searchParams.get("query")?.toString()} /> {/* Search Button */} <button type="submit" className="absolute right-0 bottom-2 mt-5 mr-4"> <svg className="w-6 h-6 text-gray-800 dark:text-black" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20" > <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z" /> </svg> </button> </form> </div> ); }
So this form will redirect user to a "use server" page, right?
// api/products/route.tsx:
import { getProducts, getProductsBySearchTerm } from "@/app/db/models/products";
import { NextResponse } from "next/server";

export async function GET(request: Request) {
const products = await getProducts();

// console.log(products);

return NextResponse.json(
{
status: 200,
message: "Success get all products",
data: products,
},
{
status: 200,
}
);
}

export async function POST(request: Request) {
const { searchTerm } = await request.json();

const products = await getProductsBySearchTerm(searchTerm);

console.log(products, "<<<<");

return NextResponse.json(
{
status: 200,
message: "Success get all products",
data: products,
},
{
status: 200,
}
);
}
send the function getProductsBySearchTerm from @/app/db/models/products
I'll help you modify it
// db/models/products.tsx
import { ObjectId } from "mongodb";
import { getMongoClientInstance } from "../config";

const DB_NAME = "games";
const COLLECTION_NAME = "products";

export type ProductModel = {
_id: ObjectId;
name: string;
slug: string;
description: string;
excerpt: string;
price: number;
tags: string[];
thumbnail: string;
images: string[];
createdAt?: Date;
updatedAt?: Date;
};

export type ProductCreateInputType = Omit<
ProductModel,
"createdAt" | "updatedAt"
>;

const getDB = async () => {
const client = await getMongoClientInstance();
const db = client.db(DB_NAME);
return db;
};

export const getProducts = async () => {
const collection = (await getDB()).collection(COLLECTION_NAME);
const Game = (await collection.find({}).toArray()) as ProductModel[];
return Game;
};

export const getProductsBySearchTerm = async (searchTerm: string) => {
const collection = (await getDB()).collection(COLLECTION_NAME);
const Game = (await collection
.find({ $text: { $search: searchTerm } })
.toArray()) as ProductModel[];
// console.log(Game, "<<<<");

return Game;
};
nope i search by name
// api/products/route.tsx:
import { getProducts, getProductsBySearchTerm } from "@/app/db/models/products";
import { NextResponse } from "next/server";

export async function GET(request: Request) {
  const products = await getProducts();

  // console.log(products);

  return NextResponse.json(
    {
      status: 200,
      message: "Success get all products",
      data: products,
    },
    {
      status: 200,
    }
  );
}

export async function POST(request: Request) {
  const { searchTerm } = await request.json();

  const products = await getProductsBySearchTerm(searchTerm);

  console.log(products, "<<<<");

  return NextResponse.json(
    {
      status: 200,
      message: "Success get all products",
      data: products,
    },
    {
      status: 200,
    }
  );
}
@AmangLy nope i search by name
there is another way to achieve this, which works fine, but its not that good. the code seems to be fine, the issue must be with searchSchema
yeah
// products/games/page.tsx
"use client";
import GameCard from "@/app/components/GameCard";
import React, { useEffect, useState } from "react";
import GamesLoadingPage from "./loading";
import GameErrorPage from "./error";
import SearchForm from "@/app/components/SearchForm";

interface Game {
_id: string;
name: string;
slug: string;
description: string;
excerpt: string;
price: number;
tags: string[];
thumbnail: string;
images: string[];
}

interface GameSectionProps {
showFullDetails?: boolean;
maxDisplay?: number;
}

const GameSection: React.FC<GameSectionProps> = ({
showFullDetails,
maxDisplay,
}) => {
const [games, setGames] = useState<Game[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
const fetchGames = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch("http://localhost:3000/api/products");
const data = await response.json();

setGames(data.data);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};

fetchGames();
}, [error]);

if (loading) {
return <GamesLoadingPage />;
}

if (error) {
return <GameErrorPage error={error} />;
}

return (
<section className="py-12 bg-gray-100">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<SearchForm />
@AmangLy yeah
Is your issue resolved? And if it’s not working. I can give you a alternate solution, which is a little ineffective
just give me alternate solution i think i can recognize
@AmangLy just give me alternate solution i think i can recognize
        const products = await this.Products.find({
            name: {
                $regex: sanitizedQuery,
                $options: "i"
            }
        }, { orders: 0, sizes: 0 }).sort({ orders: -1 }).limit(limit).exec()
this is what I've used
Hey @AmangLy , I'm awaiting your reply
@AmangLy
Is your issue resolved?
export const getProducts = async (page: number = 1, pageSize: number = 10, search: string = "") => {
  const collection = (await getDB()).collection(COLLECTION_NAME);
  const skip = (page - 1) * pageSize;

  const query = search ? { name: { $regex: search, $options: "i" } } : {};

  const products = await collection.find(query)
    .skip(skip)
    .limit(pageSize)
    .toArray() as ProductModel[];

  return products;
};
Answer
i use like this solved