AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。

MongoDBと Transstack Start の統合

このガイドでは、tanStack Start とMongoDBを使用して最新の Webアプリケーションを構築する方法を説明します。TanStack Start は、TanStackエコシステムの「TanStack ルーター」や「TanStack クエリ」などのReactライブラリとフロントエンドバックエンド開発を統合するフルスタックフレームワークです。

このチュートリアルのアプリケーションは、次のレイヤーで構成されています。

  • データベース層: MongoDB はデータを保存および検索します。

  • サーバー層:TanStack Start は、フロントエンドをMongoDBデータベースに接続するためのAPIエンドポイントとロジックを提供します。

  • データ管理レイヤー: TanStack クエリは、フロントエンドのサーバーサイドの状態を管理し、データ取得、ロード状態、エラー処理のロジックを統合します。

  • プレゼンテーション レイヤー: React は、TanStack クエリ データを使用してUIを実装します。

MongoDB のドキュメントモデルではデータがJSONのようなドキュメントとして保存されるため、複雑なマッピングなしでJavaScriptオブジェクトを簡単に操作できます。これは、TanStack Start のReactコンポーネントと TypeScript インターフェースと一致します。

TanStack Query は、MongoDB の応答をキャッシュし、ロード状態を管理し、コンポーネント間でデータを同期することで、データレイヤーを効率的に取り扱います。これにより、手動の状態管理が不要になり、冗長なデータベース呼び出しが減ります。

この組み合わせは、次の機能を必要とするアプリケーションに適しています。

  • 時間の経過とともに変化する可能性のある柔軟なデータ構造

  • 最小限のクライアント側コードでリアルタイムデータ更新

  • データベースからUIへの型の安全性

  • 効率的なキャッシュとバックグラウンド データの同期

このチュートリアルでは、 MongoDBと統合する TransStack Startアプリケーションの作成について説明します。アプリケーションはサンプルレストラン データにアクセスし、その結果をローカルでホストされているサイトに表示します。これには、 MongoDB AtlasでホストされているMongoDBクラスターを接続し、データベースの情報にアクセスして表示する手順が含まれています。

Tip

TransStack Start ではなくNode.jsドライバーを使用してMongoDBに接続する場合は、 「 Node.jsドライバーを使い始める 」ガイドを参照してください。

このセクションの手順に従って、プロジェクトの依存関係のインストール、Atlas クラスターの作成、アプリケーションディレクトリの設定を行います。

1

クイック スタートアプリケーションを作成するには、次のソフトウェアがインストールされていることを確認してください。

前提条件
ノート

バージョン 20 以降を使用します。

コードエディター

このチュートリアルでは Visual Studio Code を使用しますが、お好みのエディターを使用できます。

ターミナル

MacOS ユーザーの場合は、 ターミナル または 類似アプリを使用します。Windowsユーザーの場合は、 PowerShell を使用します。

2

MongoDB Atlas は、 MongoDB配置をホストするフルマネージドクラウドデータベースサービスです。MongoDBの配置がない 場合は、MongoDBを使い始める チュートリアルを完了して、無料のクラスター(クレジットカードは不要)を作成します。MongoDBを使い始める チュートリアルでは、このチュートリアルで使用される sample_restaurantsデータベースを含むサンプルデータベースをクラスターにロードする方法も説明します。

クラスターに接続するには、接続 URI を使用する必要があります。接続 URI を取得するには、Atlas ドキュメントのクラスターへの接続チュートリアルの手順に従います。

Tip

接続 URI を安全なロケーションに保存します。

3

公式の TransStack Start CLI を使用して、プロジェクトのスケルトンを初期化します。ターミナルを開き、目的のプロジェクトディレクトリに移動します。

初期化コマンドを実行します。

npm create @tanstack/start@latest

インストールウィザードが、設定をガイドします。次のオプションを選択します。

Prompt
入力
アクション

プロジェクトの名前は何にしますか?

ご希望のプロジェクト名

名前を入力し、 Enter キーを押します

tailwind CSS を使用しますか。

はい

「Y」と入力し、 Enter キーを押します

ツールチェーンを選択します

デフォルト(なし)

[なし] を選択し、 Enter キーを押します

配置アダプターを選択します

デフォルト:(Unitro)

Enter キーを押します

プロジェクトにどのような追加オンが必要か?

なし

Enter キーを押します(TanStack クエリは手動でインストールされます)

例が必要ですか。

なし

Enter キーを押します

インストールが完了したら、プロジェクトディレクトリに移動します。

4

TanStack Start はビルド ツールとして Vite を使用します。デフォルトでは 、Vite はブラウザの依存関係をバンドルしようとします。ただし、 Node.jsドライバーはサーバー側のネイティブ モジュールである mongodb-client-encryption に依存しています。これは、ブラウザ環境に対して Vite がバンドルするときにエラーを発生させます。

これを防ぐために、mongodb-client-encryption モジュールを最適化とサーバー側のレンダリングから除外するように Vite を設定します。

プロジェクトルートの vite.config.ts に移動し、内容を次のコードで置き換えます。

vite.config.ts

import { defineConfig } from 'vite'import { devtools } from '@tanstack/devtools-vite'import { tanstackStart } from '@tanstack/react-start/plugin/vite'import viteReact from '@vitejs/plugin-react'import viteTsConfigPaths from 'vite-tsconfig-paths'import tailwindcss from '@tailwindcss/vite'import { nitro } from 'nitro/vite' const config = defineConfig({ plugins: [ devtools(), nitro(), // this is the plugin that enables path aliases viteTsConfigPaths({ projects: ['./tsconfig.json'], }), tailwindcss(), tanstackStart(), viteReact(), ], optimizeDeps: { // Exclude this server-side dependency to avoid bundling errors exclude: ['mongodb-client-encryption'], }, ssr: { // Ensure this module is externalized during server-side rendering external: ['mongodb-client-encryption'], },}) export default config
5

Node.jsドライバー をインストールして、サーバーコードがデータベースに接続できるようにし、TanStack クエリをインストールしてフロントエンドでのデータ取得を管理します。

プロジェクトルートで次のコマンドを実行します。

npm install mongodb @tanstack/react-query
6

インストール ウィザードによって不要なファイルが作成されました。プロジェクトをクリーンな状態に維持し、自動インポートの混乱を避けるためには、data ディレクトリと demo ディレクトリを削除してください。

プロジェクトルートで次のコマンドを実行します。

rm -rf src/datarm -rf src/routes/demo

プロジェクト構造を設定したら、このセクションの手順に従ってバックエンドを設定します。

1

接続 URI を安全に保存するには、プロジェクトのルートに .envファイルを作成します。

プロジェクトルートで次のコマンドを実行します。

touch .env

.envファイルを開き、接続 URI を追加します。

MONGODB_URI=<Your Connection URI>

注意

<Your Connection URI> をMongoDB Atlasから受信した接続 URI に置き換えます。

2

MongoDBクライアント を初期化するための専用の TypeScriptファイルを作成します。

プロジェクトルートで次のコマンドを実行して、ファイル構造を作成します。

mkdir -p src/libtouch src/lib/db.ts

src/lib/db.ts を開き、次のコードを貼り付けます。

src/lib/db.ts

import { MongoClient } from "mongodb" // Connection string from the MongoDB atlas dashboardconst uri = process.env.MONGODB_URI let connected = falselet client: MongoClient export async function connectToDatabase() { if (!uri) { throw new Error("MONGODB_URI is not defined in environment variables") } if (!connected) { try { client = new MongoClient(uri) await client.connect() connected = true } catch (error) { throw new Error(`Failed to connect to database: ${error instanceof Error ? error.message : 'Unknown error'}`) } } return client.db("sample_restaurants")}

このファイルには、 MongoDBクラスターと sample_restaurantsデータベースに接続する connectToDatabase() 関数が含まれています。sample_restaurantsデータベースには、レストラン名、料理名、地区、住所情報などのフィールドを含む、ニューヨーク市のレストラン データが含まれています。

3

TransStack Start はサーバー関数 を使用して、サーバー上でコードを安全に実行します。データベースクエリを処理するための専用ファイルを作成します。

プロジェクトルートで次のコマンドを実行して、restaurants.tsファイルを作成します。

mkdir -p src/servertouch src/server/restaurants.ts

src/server/restaurants.ts を開き、次のコードを貼り付けます。

src/サーバー/restaurants.ts

import { createServerFn } from "@tanstack/react-start"import { connectToDatabase } from "../lib/db" export interface Restaurant { _id: string address: { building: string coord: [number, number] street: string zipcode: string } borough: string cuisine: string name: string restaurant_id: string} // Gets a list of all restaurants from the databaseexport const getAllRestaurants = createServerFn({ method: 'GET'}).handler(async () => { const db = await connectToDatabase() const restaurants = await db .collection<Restaurant>("restaurants") .find({}) .limit(100) .toArray() return restaurants.map((restaurant) => ({ ...restaurant, _id: restaurant._id.toString(), }))}) // Gets a list of restaurants in Queens with "Moon" in the nameexport const getRestaurantsByBorough = createServerFn({ method: 'GET'}).handler(async () => { const db = await connectToDatabase() const restaurants = await db .collection<Restaurant>("restaurants") .find({ borough: 'Queens', name: {$regex: 'Moon', $options: 'i'} // case-insensitive match }) .limit(100) .toArray() // Convert ObjectId to string for client-side serialization return restaurants.map((restaurant) => ({ ...restaurant, _id: restaurant._id.toString(), })) })

このファイルには、getAllRestaurants() と getRestaurantsByBorough() の 2 つの関数が含まれています。この 2 つの関数はMongoDBクラスターをクエリし、要求されたデータを返します。

データベース層とサーバーレイヤーを設定したら、このセクションの手順に従って、 データ管理層と表示レイヤーを完了します。

1

src/components/Header.tsx に移動し、コンテンツを次のコードで置き換えます。

src/components/header.tsx

import { Link } from "@tanstack/react-router" export function Header() { return( <> <nav className="bg-white px-6 py-2 shadow-md"> <div className="flex justify-between items-center gap-8"> <Link to ="/"> <img alt="MongoDB logo" className="h-10 inline" src="https://d3cy9zhslanhfa.cloudfront.net/media/3800C044-6298-4575-A05D5C6B7623EE37/4B45D0EC-3482-4759-82DA37D8EA07D229/webimage-8A27671A-8A53-45DC-89D7BF8537F15A0D.png" width="120" height="40" loading="eager" style={{ maxHeight: '2.5rem', width: 'auto' }} /> </Link> <Link to ="/browse" className="text-lime-800 text-lg font-semibold hover:text-green-700"> Browse </Link> </div> </nav> </> )}

このコンポーネントはレストランの結果の上にある ヘッダーをレンダーし、参照リンクとロゴが含まれます。これらにより、ルート間を移動できます。

2

プロジェクトルートから次のコマンドを実行して、RestaurantList コンポーネントを作成します。

touch src/components/RestaurantList.tsx

src/components/RestaurantList.tsx に次のコードを貼り付けてください。

src/components/RestaurantList.tsx

import {Restaurant} from "../server/restaurants" type Props = { restaurants: Restaurant[]} export function RestaurantList({restaurants}: Props) { return ( <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md"> <table className="w-full"> <thead className="bg-gray-50"> <tr> <th className="px-4 py-3 text-left text-sm font-bold text-gray-700">Name</th> <th className="px-4 py-3 text-left text-sm font-bold text-gray-700">Borough</th> <th className="px-4 py-3 text-left text-sm font-bold text-gray-700">Cuisine</th> </tr> </thead> <tbody className="divide-y divide-gray-200"> {restaurants.map((restaurant) => ( <tr key={restaurant._id}> <td className="px-4 py-3">{restaurant.name}</td> <td className="px-4 py-3">{restaurant.borough}</td> <td className="px-4 py-3">{restaurant.cuisine}</td> </tr> ))} </tbody> </table> </div> )}

このコンポーネントはレストランの表示を取り扱います。クエリ データはプロパティとして処理され、プロパティはテーブル内に表示されます。

3

src/routes/__root.tsx に移動します。__root.tsx の内容を次のコードで置き換えます。

src/ route/__ root.tsx

import { HeadContent, Scripts, createRootRoute, Outlet } from '@tanstack/react-router'import { QueryClient, QueryClientProvider } from '@tanstack/react-query'import '../styles.css' import {Header} from '../components/Header' //Configure TanStack Query Client with cache and retry optionsconst queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60 * 1000, // Data stays fresh for one minute retry: 1, // Retry failed requests once retryDelay: 1000 // Wait one second before retrying }, },}) export const Route = createRootRoute({ component: () => ( <html lang="en"> <head> <HeadContent /> </head> <body> <QueryClientProvider client={queryClient}> <Header /> <main> <Outlet /> </main> </QueryClientProvider> <Scripts /> </body> </html> ), // Handle 404 errors for non-existent routes notFoundComponent: () => { return ( <div className="p-6"> <h1 className="text-2xl font-bold">404 - Page Not Found</h1> <p>The page you're looking for doesn't exist.</p> </div> ) }})

このファイルは、アプリケーション全体を囲むラッパーです。このコードでは QueryClientProvider を使用して、TanStack クエリがデータ状態を管理できるようにします。

4

src/routes/index.tsx に移動します。index.tsx の内容を次のコードで置き換えます。

src/ route/ インデックス.tsx

import { createFileRoute } from "@tanstack/react-router";import {useSuspenseQuery} from '@tanstack/react-query'import { RestaurantList } from "../components/RestaurantList";import { getAllRestaurants } from "../server/restaurants"; export const Route = createFileRoute('/')({ component: Home, pendingComponent: () => ( <div className="p-6 text-gray-500"> Loading restaurants... </div> ), errorComponent: ({error}) => ( <div className="p-6 text-red-600"> <h2 className="text-xl font-bold">Connection Error</h2> <p>{error.message}</p> <p className="text-sm mt-2">Please check your MongoDB connection string in your .env file</p> </div> ),}) function Home() { const{data: restaurants} = useSuspenseQuery({ queryKey:['restaurants'], queryFn: () => getAllRestaurants(), }) return ( <div className="w-full p-6"> <h2 className="text-lg font-semibold p-4">All Restaurants</h2> <RestaurantList restaurants={restaurants} /> </div> )}

このルートは、Header コンポーネントと RestaurantList コンポーネントを使用して getAllRestaurants() の結果を表示します。

5

プロジェクトルートから次のコマンドを実行して、browse.tsx ルートを作成します。

touch src/routes/browse.tsx

src/routes/browse.tsx に次のコードを貼り付けてください。

src/ route/browse.tsx

import { createFileRoute } from '@tanstack/react-router'import { useSuspenseQuery } from '@tanstack/react-query'import { RestaurantList } from '../components/RestaurantList'import { getRestaurantsByBorough } from '../server/restaurants' export const Route = createFileRoute('/browse')({ component: BrowsePage, // Display error UI if MongoDB connection or query fails errorComponent: ({ error }) => ( <div className="p-6 text-red-600"> <h2 className="text-xl font-bold">Connection Error</h2> <p>{error.message}</p> <p className="text-sm mt-2"> Please check your MongoDB connection string in your .env file </p> </div> ),}) function BrowsePage() { // Fetch filtered restaurants using TanStack Query // Query includes borough and search term in the key for proper caching const { data: restaurants } = useSuspenseQuery({ queryKey: ['restaurants', 'queens', 'moon'], // Unique cache key for this filtered query queryFn: () => getRestaurantsByBorough(), // Server function with MongoDB filter }) return ( <div className='w-full p-6'> <h2 className='text-lg font-semibold p-4'> Queens Restaurants with "Moon" in the Name </h2> <RestaurantList restaurants={restaurants} /> </div> )}

このページには、sample_restaurantsデータベースのフィルターされたクエリが表示されます。名前に Moon が含まれるクイーンズのすべてのレストランが表示されます。また、Header コンポーネントと RestaurantList コンポーネントも使用します。

注意

サーバーを実行するまで、createFileRoute 行に IDE に赤色の警告が表示されることがあります。これは正常です。TransStack ルーターは、アプリケーションを初めて npm run dev で実行するときに、ルートに必要な TypeScript タイプの定義を生成します。サーバーが起動すると、警告は消えます。

6

続行する前に、ファイルのツリーが以下の構造と完全に一致していることを確認してください。追加のプロジェクトファイルは無視しても問題ありません。

your-app/├─ node_modules/├─ public/├─ src/│ ├─ components/│ │ ├─ Header.tsx <-- Logo and browse link│ │ ├─ RestaurantList.tsx <-- Table that displays results of DB query│ ├─ routes/│ │ ├─ __root.tsx <-- Application wrapper│ │ ├─ browse.tsx <-- Browse page, holds results of getRestaurantsByBorough()│ │ ├─ index.tsx <-- Home page, holds results of getAllRestaurants()│ ├─ server/│ │ ├─ restaurants.ts <--- Server functions│ ├─ lib/│ │ ├─ db.ts <--- Database connection├─ .env <-- Connection URI

残りの手順に従ってサーバーを起動し、レンダリングされたレストラン データを表示します。

1

プロジェクトルートで次のコマンドを実行して、開発サーバーを起動します。

npm run dev

成功した場合、コマンドはターミナルに次の情報を出力します。

VITE v7.2.4 ready in 939 ms ➜ Local: http://localhost:3000/➜ Network: use --host to expose➜ press h + enter to show help
2

ブラウザで http://localhost:3000/ を開きます。最初のランディング ページには、sample_restaurantsデータベース内のすべてのレストランが表示されます。

sample_restaurantsデータベース内のすべてのレストランを表示するランディングアプリ
3

ヘッダーの [Browse リンクをクリックすると、名前が Moon となるクイーンズ内のレストランのフィルターされたリストが表示されます。

ブラウザページには、 sample_restaurantsデータベースからのフィルタリングされたレストランが表示されます。

クイック スタート チュートリアルが完了しました。

これらの手順を完了すると、 MongoDBの配置に接続し、サンプルのレストラン データに対してクエリを実行し、結果をリアルタイムの応答性でレンダーするTanStack Startアプリケーションが作成されます。

TanStack Start、TanStackエコシステム、 MongoDBの詳細については、次のリソースを表示します。