Docs 菜单
Docs 主页
/ /

将MongoDB与 Nuxt 和 Vue 集成

本教程将指导您构建使用 Vue 并与MongoDB集成的 Nuxt应用程序。 Nuxt 是一个 Vue框架,可通过其 Nitro服务器引擎提供基于文件的路由、服务器端渲染和内置API路由。 Nuxt 与 Vue 相结合,可让您无需单独的后端服务器即可构建完整的应用程序。

本教程中的应用程序包含以下层:

  • 数据库层:MongoDB提供数据存储和检索

  • 服务器层:Nuxt服务器路由处理API逻辑和数据库交互

  • 表示层:Vue 使用响应式数据绑定实现用户界面

Nuxt 基于 Vue 构建,为服务器路由提供带有 Node.js 运行时的全栈框架,非常适合MongoDB Node.js驾驶员。您可以直接从 Nuxt服务器路由或服务器端实用程序连接到MongoDB ,并将文档返回到 Vue 组件,而无需维护单独的后端服务或API层。

MongoDB 灵活的文档结构可轻松映射到JavaScript对象。因此,无论您使用的是 Options API还是 Composition API ,您都可以在 Vue 组件中无缝使用MongoDB数据。从MongoDB获取的文档可以直接传递到组件和模板中,从而减少了对复杂数据转换或额外对象关系映射 (ORM) 层的需求。

Nuxt 的服务器端渲染 (SSR) 和数据获取实用程序允许您在渲染页面之前查询服务器上的MongoDB 。这样,您就可以使用即用型数据来充实 Vue 组件,从而提高数据驱动型应用程序的感知性能和 SEO。

本教程向您展示如何使用 Nuxt 和 Vue构建Web应用程序。该应用程序访问示例餐厅数据,查询数据,并在本地托管站点上显示结果。本教程还包括有关连接到MongoDB Atlas上托管的MongoDB 集群以及访问和显示数据库中的数据的说明。

提示

如果您希望使用 Node.js驾驶员而不使用 Nuxt 连接到MongoDB ,请参阅 Node.js驱动程序程序入门指南。

按照本节中的步骤安装项目依赖项、创建Atlas集群并设立应用程序目录。

1

要创建快速入门应用程序,请在开发环境中安装以下软件:

先决条件

注意

使用 20 或更高版本。

代码编辑器

本教程使用Visual Studio Code,但你也可以使用自己选择的编辑器。

终端应用和shell

对于 macOS 或Linux用户,请使用 终端 或类似应用。对于Windows用户,请使用 PowerShell。

2

MongoDB Atlas是一项完全托管云数据库服务,用于托管MongoDB部署。如果您没有MongoDB 部署,可以通过完成MongoDB入门教程免费创建MongoDB 集群(无需信用)。

提示

确保sample_restaurants 数据集已加载到集群中。本教程查询该数据集中的数据。要学习;了解如何将sample_restaurants 数据集加载到集群中,请参阅MongoDB入门教程。

要连接到MongoDB集群,您必须使用连接 URI。学习如何检索连接 URI,请参阅MongoDB入门教程的添加连接字符串部分。

提示

将MongoDB Atlas连接字符串保存在安全位置。您将在后续步骤中将其添加到 .env文件中。

3

使用官方 Nuxt CLI使用 Vue 初始化新的 Nuxt项目。打开终端并导航到所需的项目目录。

运行初始化命令:

npm create nuxt@latest

CLI会提示您配置项目。使用以下响应:

  1. 提示:需要安装以下软件包:create-nuxt@latest-number。确定要继续吗?

    响应:键入 y并按 Enter 键。

  2. 提示:您想使用哪个模板?

    响应:选择 minimal - Minimal setup for Nuxt 4 (recommended)

  3. 提示:您想在哪里创建项目?

    响应:按 Enter接受默认目录或键入其他路径。

  4. 提示:您想使用哪个包管理器?

    响应:选择 npm

  5. 提示:初始化 git存储库?

    响应:根据您的偏好选择 YesNo或 。

  6. 提示:您想安装任何官方模块吗?

    响应:选择 No

4

导航到项目目录并通过运行以下命令来安装MongoDB驾驶员、Lucide 图标、Tailwind 和相关依赖项:

npm install mongodb lucide-vue-next
npm install -D @types/node @nuxtjs/tailwindcss

您可以安全地忽略 Tailwind 安装中有关已弃用软件包的任何警告。

设置项目结构后,请按照本节中的步骤设立后端。

1

在项目根目录中创建一个 .env文件,通过在项目根目录中运行以下命令来安全地存储连接 URI:

touch .env

打开 .env文件并添加连接 URI:

MONGODB_URI=<Your Connection URI>

注意

将从MongoDB Atlas收到的连接 URI 替换为 <Your Connection URI>

2

打开项目根目录中的 nuxt.config.ts文件,并将其内容替换为以下代码,以加载环境变量并配置 Tailwind CSS 模块:

nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
future:{
compatibilityVersion: 4,
},
runtimeConfig:{
// Server-side only config. Not exposed to the client
mongoURI: process.env.MONGODB_URI,
},
css:['@/assets/css/main.css'],
modules: ['@nuxtjs/tailwindcss'],
})

nuxt.config.ts文件从 .env文件加载环境变量,并配置 Tailwind支持以设置 Vue 组件的样式。

3

在项目根目录中运行以下命令,创建一个实用程序文件来保存MongoDB连接逻辑:

mkdir -p server/utils
touch server/utils/mongodb.ts

打开 server/utils/mongodb.ts文件并添加以下代码:

服务器/utils/mongodb.ts
import { MongoClient, type Db } from "mongodb";
let cachedClient: MongoClient | null = null;
let cachedDb: Db | null = null;
export async function connectToDatabase(){
if (cachedClient && cachedDb){
return { client: cachedClient, db: cachedDb };
}
const config = useRuntimeConfig();
const uri = config.mongoURI;
if (!uri){
throw new Error("Please define the MONGO_URI environment variable inside .env");
}
const client = new MongoClient(uri);
await client.connect();
const db = client.db("sample_restaurants");
cachedClient = client;
cachedDb = db;
console.log("Connected to MongoDB Atlas");
return { client, db };
}

此代码创建一个可重用的MongoDB客户端,该客户端使用存储在环境变量中的连接 URI 连接到Atlas 集群。客户端连接到 sample_restaurants数据库,其中包含有关纽约市各地餐馆的信息。

4

Nuxt服务器路由处理API请求并与数据库交互。在项目根目录中运行以下命令,创建用于获取餐厅数据的服务器路由:

mkdir -p server/api/restaurants
touch server/api/restaurants/index.get.ts

打开 server/api/restaurants/index.get.ts文件并添加以下代码:

服务器 索引
import { connectToDatabase } from "~~/server/utils/mongodb";
export default defineEventHandler(async () =>{
const { db } = await connectToDatabase();
const collection = db.collection("restaurants");
const restaurants = await collection
.find({})
.limit(50)
.project({ name: 1, borough: 1, cuisine: 1, grades: 1})
.toArray();
return restaurants.map((doc) => ({
...doc,
_id: doc._id.toString(),
}))
})

此文件定义查询 restaurants集合的服务器路由。它检索前 50 个餐厅文档,并将其作为JSON响应返回。

5

在项目根目录中运行以下命令以创建新的路由文件:

touch server/api/restaurants/browse.get.ts

打开 server/api/restaurants/browse.get.ts文件并添加以下代码:

服务器/api/restaurants/browse.get.ts
import { connectToDatabase } from '~~/server/utils/mongodb'
export default defineEventHandler(async () => {
const { db } = await connectToDatabase();
const collection = db.collection("restaurants");
// Filter: Queens borough + name contains "Moon" (case-insensitive)
const query = {
borough: 'Queens',
name: { $regex: 'Moon', $options: 'i' },
}
const restaurants = await collection
.find(query)
.project({ name: 1, borough: 1, cuisine: 1, grades: 1 })
.toArray()
return restaurants.map((doc) => ({
...doc,
_id: doc._id.toString(),
}))
})

此文件定义一条服务器路由,用于查询 sample_restaurants数据库中位于 Queens 且其名称中包含单词 Moon 的餐厅,并以JSON响应的形式返回匹配文档。

设置后端后,请按照本节中的步骤为应用程序设立表示层。

1

在项目根目录中运行以下命令,为主全局样式创建 CSS文件:

mkdir -p app/assets/css
touch app/assets/css/main.css

打开 app/assets/css/main.css文件并添加以下代码:

应用/assets/css/main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

此文件导入 Tailwind CSS 指令,这些指令生成用于设计应用程序样式的实用程序类。 Tailwind 提供了设立针对布局、间距、颜色和排版的预构建类,而无需自定义 CSS。

2

在项目根目录中运行以下命令,创建用于显示餐厅数据的 Vue 组件:

mkdir -p app/components
touch app/components/RestaurantList.vue

打开 app/components/RestaurantList.vue文件并添加以下代码:

应用/components/RestaurantList.vue
<script setup lang="ts">
import { computed } from 'vue'
import { MapPin, Utensils, ChevronRight } from 'lucide-vue-next'
// Type definitions
interface Grade {
grade?: string
score?: number
}
interface Restaurant {
_id: string
name: string
borough?: string
cuisine?: string
grades?: Grade[]
}
// Determine endpoint based on current route
const route = useRoute()
const isBrowse = computed(() => route.path === '/browse')
const endpoint = computed(() =>
isBrowse.value ? '/api/restaurants/browse' : '/api/restaurants'
)
// Fetch data using Nuxt's useFetch composable
// Automatically refetches when endpoint changes
const { data: restaurants } = await useFetch<Restaurant[]>(endpoint, {
watch: [endpoint],
default: () => [],
})
// Dynamic page content
const pageTitle = computed(() =>
isBrowse.value ? 'Hidden Gems in Queens' : 'All Restaurants'
)
const pageSubtitle = computed(() =>
isBrowse.value
? "Filtered by: Borough 'Queens' & Name contains 'Moon'"
: 'Explore our complete directory of local favorites'
)
// Deterministic gradient based on name length
const getGradient = (name: string) => {
const gradients = [
'from-orange-400 to-pink-500',
'from-blue-400 to-indigo-500',
'from-green-400 to-emerald-500',
'from-purple-400 to-fuchsia-500',
]
return gradients[name.length % gradients.length]
}
</script>
<template>
<div class="max-w-6xl mx-auto px-4 py-8">
<!-- Header -->
<div class="mb-8">
<h3 class="text-3xl font-bold text-gray-800">
{{ pageTitle }}
</h3>
<p class="text-gray-500 mt-2">
{{ pageSubtitle }}
</p>
</div>
<!-- Restaurant Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="restaurant in restaurants"
:key="restaurant._id"
class="group bg-white rounded-2xl border border-gray-100 shadow-sm hover:shadow-xl hover:-translate-y-1 transition-all duration-300 overflow-hidden flex flex-col"
>
<!-- Gradient Header -->
<div
:class="[
'h-32 bg-gradient-to-br p-6 flex items-end relative',
getGradient(restaurant.name)
]"
>
<span class="absolute top-4 right-4 bg-white/20 backdrop-blur-md text-white text-xs font-bold px-2 py-1 rounded-full border border-white/30">
Grade {{ restaurant.grades?.[0]?.grade ?? 'N/A' }}
</span>
<h3 class="text-white text-xl font-bold drop-shadow-md line-clamp-2">
{{ restaurant.name }}
</h3>
</div>
<!-- Card Body -->
<div class="p-5 flex-1 flex flex-col">
<div class="flex items-center justify-between mb-4">
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium bg-green-50 text-green-700 border border-green-100">
<Utensils class="w-3 h-3" />
{{ restaurant.cuisine ?? 'Unknown' }}
</span>
<div class="flex items-center text-gray-400 text-xs font-medium">
<MapPin class="w-3 h-3 mr-1" />
{{ restaurant.borough ?? 'Unknown' }}
</div>
</div>
<div class="mt-auto pt-4 border-t border-gray-50 flex items-center justify-between text-sm">
<span class="text-gray-400">
Score: {{ restaurant.grades?.[0]?.score ?? 0 }}
</span>
<button class="text-indigo-600 font-semibold group-hover:underline flex items-center gap-1">
View Menu <ChevronRight class="w-4 h-4" />
</button>
</div>
</div>
</div>
</div>
<!-- Empty State -->
<div v-if="restaurants?.length === 0" class="text-center py-12 text-gray-500">
<p>No restaurants found.</p>
<p class="text-sm mt-2">Check your MongoDB connection and ensure the sample_restaurants database is loaded.</p>
</div>
</div>
</template>

此 Vue 组件从 Nuxt服务器路由获取餐厅数据,并将其显示在响应式网格布局中。它会根据当前路线动态调整API端点和页面内容,显示所有餐厅或筛选后的结果。

3

在项目根目录中运行以下命令,为导航栏创建 Vue 组件:

touch app/components/Navbar.vue

打开 app/components/Navbar.vue文件并添加以下代码:

应用/components/Navbar.vue
<template>
<nav class="flex justify-between items-center mb-6 bg-white shadow-md px-6 py-4 rounded-lg">
<NuxtLink to="/">
<img
alt="MongoDB logo"
class="h-10"
src="https://d3cy9zhslanhfa.cloudfront.net/media/3800C044-6298-4575-A05D5C6B7623EE37/4B45D0EC-3482-4759-82DA37D8EA07D229/webimage-8A27671A-8A53-45DC-89D7BF8537F15A0D.png"
/>
</NuxtLink>
<div class="flex gap-4">
<NuxtLink
to="/"
class="px-4 py-2 rounded-lg text-sm font-medium transition-colors"
:class="$route.path === '/'
? 'bg-indigo-100 text-indigo-700'
: 'text-gray-600 hover:bg-gray-100'"
>
All Restaurants
</NuxtLink>
<NuxtLink
to="/browse"
class="px-4 py-2 rounded-lg text-sm font-medium transition-colors"
:class="$route.path === '/browse'
? 'bg-indigo-100 text-indigo-700'
: 'text-gray-600 hover:bg-gray-100'"
>
Browse Filtered
</NuxtLink>
</div>
</nav>
</template>

此 Vue 组件在餐厅结果上方呈现导航栏,并包含 All RestaurantsFiltered Restaurants 链接。这些允许您在路线之间导航。

4

在项目根目录中运行以下命令,为应用程序创建索引页面:

mkdir -p app/pages
touch app/pages/index.vue

打开 app/pages/index.vue文件并添加以下代码:

应用 索引
<template>
<RestaurantList />
</template>

此文件使用 RestaurantListNavbar 组件显示来自 index.get.ts服务器路由的结果。

5

在项目根目录中运行以下命令,创建一个新的 Vue 页面,用于显示筛选后的餐厅数据:

touch app/pages/browse.vue

打开 app/pages/browse.vue文件并添加以下代码:

应用/pages/browse.vue
<template>
<RestaurantList />
</template>

此文件显示对 sample_restaurants数据库进行筛选的查询结果,该查询返回 Queens 名称中包含单词 Moon 的所有餐厅。它还使用 RestaurantListNavbar 组件来构造页面。

6

打开 app/App.vue文件并将其内容替换为以下代码以连接组件:

应用/ 应用.vue
<template>
<div class="w-full p-6 min-h-screen bg-gray-50">
<Navbar />
<NuxtPage />
</div>
</template>
7

在继续之前,请确保您的文件树与以下结构密切匹配。您可以安全地忽略任何其他项目文件。

your-project-directory/
├── .env <-- Environment variable file
├── app/
│ ├── app.vue <-- Main application component
│ ├── assets/
│ │ └── css/
│ │ └── main.css <-- Tailwind config
│ ├── components/
│ │ ├── Navbar.vue <-- All restaurants and filtered restaurants links
│ │ └── RestaurantList.vue <-- Container for restaurant data
│ └── pages/
│ ├── browse.vue <-- Filtered restaurants page
│ └── index.vue <-- All restaurants page
├── server/
│ ├── api/
│ │ └── restaurants/
│ │ ├── browse.get.ts <-- Filtered restaurants route
│ │ └── index.get.ts <-- All restaurants route
│ └── utils/
│ └── mongodb.ts <-- MongoDB connection utility
├── nuxt.config.ts <-- Nuxt configuration file
└── package.json

执行以下步骤,启动服务器并查看渲染的餐厅数据。

1

在项目根目录中运行以下命令以启动开发服务器:

npm run dev

如果成功,该命令将在终端输出以下信息:

Nuxt 4.2.2 (with Nitro 2.13.1, Vite 7.3.1 and Vue 3.5.27)
Local: http://localhost:3000/
Network: use --host to expose
Using default Tailwind CSS file
DevTools: press Shift + Option + D in the browser (v3.1.1)
Vite client built in 22ms
Vite server built in 19ms
Nuxt Nitro server built in 247ms
Vite server warmed up in 0ms
Vite client warmed up in 1ms
Connected to MongoDB Atlas
2

在浏览器中打开 http://localhost:3000/。初始登陆页面显示 sample_restaurants数据库中的前 50 家餐厅。

显示 sample_restaurants数据库中前 50 家餐厅的登陆应用。
3

单击导航栏中的 Filtered Restaurants 链接,查看筛选后的餐厅结果。该页面显示 Queens 中名称中包含 Moon 一词的所有餐厅。

筛选的餐厅页面显示了皇后区名称中包含“Moon”一词的所有餐厅。

恭喜您完成快速入门教程!

完成这些步骤后,您就拥有了一个 Nuxt 和 Vue应用程序,它可以连接到MongoDB 部署、对示例餐厅数据运行查询,并在浏览器中呈现结果。

要学习;了解有关使用MongoDB、 Nuxt 和 Vue 的更多信息,请查看以下资源:

后退

Meteor 和 Vue 集成

在此页面上