使用 Next.js 串接 MongoDB
MongoDB 詳細操作: https://www.notion.so/Use-MERN-stack-to-dev-Full-Stack-web-2d59def5443d80a194a5e8d6bf6d740a
我們建立好叢集和集合後,就可以去Next.js 寫上環境設定和連接了!
如果在本地測試都OK,部屬到Vercel就不行了,可能要在Vercel中加上環境變數!
環境設定
可以在專案中的 DataBase & NetWork Access 查看使用者名稱
MONGODB_URI=mongodb+srv://使用者名稱:密碼@cluster0.tend0gf.mongodb.net/資料庫名稱?appName=Cluster0Code language: JavaScript (javascript)

切記!!!!! 在專案中的 NetWork Access 設定 允許 0.0.0.0/0
接著要下載官方套件
npm install @auth/mongodb-adapter mongodb@^6.13.0Code language: CSS (css)
lib / db.ts
寫一個連線池(Connection Pool),避免因為無限制地重複連線而導致資料庫崩潰。
import { MongoClient, ServerApiVersion } from 'mongodb';
const uri = process.env.MONGODB_URI;
function createClient(): MongoClient {
if (!uri) {
throw new Error(
'請新增MONGODB_URI環境變數',
);
}
return new MongoClient(uri, {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
},
});
}
declare global {
// eslint-disable-next-line no-var
var _mongoClientPromise: Promise<MongoClient> | undefined;
}
let clientPromise: Promise<MongoClient>;
if (process.env.NODE_ENV === 'development') {
if (!global._mongoClientPromise) {
const client = createClient();
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
const client = createClient();
clientPromise = client.connect();
}
export default clientPromise;
export async function pingMongo(): Promise<boolean> {
const client = await clientPromise;
await client.db().command({ ping: 1 });
return true;
}Code language: TypeScript (typescript)
auth.tsx
上一章有講到如何使用google sso來實現登入,當使用者登入後我們當然要存下他的資料,因此我們更改我們的auth.tsx:
- 首次登入:如果是第一次登入的,Auth.js 會自動透過
clientPromise連線到 MongoDB,並在指定的資料庫中自動建立三個Collections:users、accounts與sessions。接著觸發events.createUser與events.linkAccount,可以在 Vercel 的 Logs 中看到[auth] MongoDB user created:...的訊息。
- Session 維持:每次使用者重新整理網頁或切換路由時,Auth.js 透過瀏覽器 Cookie 中的
sessionToken去 MongoDB 的sessions集合查詢該 Session 是否過期。
import NextAuth from 'next-auth';
import Google from 'next-auth/providers/google';
import { MongoDBAdapter } from '@auth/mongodb-adapter';
import clientPromise from '@/lib/db';
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: MongoDBAdapter(clientPromise),
providers: [
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
}),
],
secret: process.env.AUTH_SECRET,
trustHost: true,
pages: {
signIn: '/login',
},
session: {
strategy: 'database',
},
callbacks: {
async session({ session, user }) {
if (session.user && user.id) {
session.user.id = user.id;
}
return session;
},
},
events: {
async createUser({ user }) {
console.info('[auth] MongoDB user created:', user.id, user.email);
},
async linkAccount({ user }) {
console.info('[auth] Account linked for user:', user.id);
},
},
});Code language: JavaScript (javascript)
update 資料到MongoDB
使用Server action。我們可以在Server action中(也就是後端)把資料塞進資料庫。
import { auth } from '@/auth';
import { clientPromise } from '@/lib/db';
/**
* 萬用模板:新增或更新資料到指定的 Collection
* @param data 欲存入的資料內容(可根據需求定義型別)
*/
export async function saveSomethingToDb(data: any): Promise<{ success: boolean; message?: string }> {
// 1. 安全防禦:檢查使用者是否登入
const session = await auth();
if (!session?.user?.id) {
return { success: false, message: '儲存失敗:使用者尚未登入' };
}
try {
// 2. 獲取資料庫連線與實例
const client = await clientPromise;
const db = client.db();
// 3. 執行資料庫寫入動作 (使用 updateOne + upsert)
const COLLECTION_NAME = 'YOUR_COLLECTION_NAME'; // 改成你資料表的名稱 (例如: user_profiles, bookmarks)
await db.collection(COLLECTION_NAME).updateOne(
{ userId: session.user.id }, // 查詢條件:確保這筆資料牢牢綁定在目前登入的使用者身上
{
$set: {
// 改成想塞入的欄位與資料格式
yourDataKey: data,
updatedAt: new Date(), // 順便記錄最後修改時間
},
// 如果是全新檔案,想在建立時加入「建立時間」,可以使用 $setOnInsert
$setOnInsert: {
createdAt: new Date(),
}
},
{ upsert: true } // 如果找不到該 userId 的文件就「直接新增」;如果找到了就「局部更新」欄位
);
return { success: true };
} catch (error) {
// 4. 錯誤捕捉與日誌紀錄
console.error(`[saveSomethingToDb][${new Date().toISOString()}]`, error);
return { success: false, message: '伺服器內部錯誤,請稍後再試' };
}
}Code language: JavaScript (javascript) 