Astro,年轻人推荐的新玩具,准备在我家的NAS上做个测试

使用 MongoDB Atlas 的云端服务替代本地 MongoDB 部署是一个方便且高效的选择,特别适合云端项目。以下是如何在当前项目中集成 MongoDB Atlas 的具体步骤。


步骤 1:创建 MongoDB Atlas 集群

  1. 注册 MongoDB Atlas

    • 前往 MongoDB Atlas 注册账号。
    • 登录后,点击 “Build a Database” 创建一个新集群。
  2. 选择集群配置

    • 选择免费层(M0 Shared Cluster)或付费层。
    • 选择集群位置(建议选择离服务器最近的地区)。
  3. 创建数据库用户

    • 在 Security > Database Access 中,点击 “Add New Database User”
    • 设置用户名和密码(如 astro-userastro-password)。
    • 分配权限为 “Read and Write to Any Database”
  4. 允许 IP 访问

    • 在 Security > Network Access 中,点击 “Add IP Address”
    • 选择 “Allow Access from Anywhere”(仅限开发阶段),或添加特定服务器的 IP。
  5. 获取连接字符串

    • 在集群页面,点击 “Connect” > “Drivers”,复制连接字符串,例如:
      mongodb+srv://astro-user:[email protected]/blog?retryWrites=true&w=majority
      

步骤 2:修改 docker-compose.yaml

将 MongoDB Atlas 的连接字符串集成到 astro 服务的环境变量中:

修改 docker-compose.yaml

services:
  astro:
    build:
      context: ./astro
    container_name: astro
    ports:
      - "9090:3000"
    environment:
      MONGO_URI: mongodb+srv://astro-user:[email protected]/blog?retryWrites=true&w=majority
    env_file:
      - ./astro/.env
    command: npm start

步骤 3:Astro 项目中集成 MongoDB Atlas

在 Astro 项目中,使用连接字符串连接到 MongoDB Atlas。

示例:获取博客文章

src/pages/blog/index.astro 中:

---
import { MongoClient } from "mongodb";

const uri = import.meta.env.MONGO_URI; // 从环境变量获取 MongoDB URI
const client = new MongoClient(uri);

await client.connect();
const db = client.db("blog"); // 使用数据库名称
const posts = await db.collection("posts").find({}).toArray();
---
<html>
  <body>
    <h1>博客文章列表</h1>
    <ul>
      {posts.map((post) => (
        <li>
          <a href={`/blog/${post._id}`}>{post.title}</a>
          <p>{post.content.slice(0, 100)}...</p>
        </li>
      ))}
    </ul>
  </body>
</html>

步骤 4:隐藏敏感信息

将敏感信息(如连接字符串)存储在 .env 文件中,确保不会直接写入代码。

创建 .env 文件

astro 目录下创建 .env

MONGO_URI=mongodb+srv://astro-user:[email protected]/blog?retryWrites=true&w=majority
S3_ENDPOINT=http://*****
S3_BUCKET=astro
S3_ACCESS_KEY=*****
S3_SECRET_KEY=*****

修改 docker-compose.yaml

将环境变量文件加载到 astro 服务中:

services:
  astro:
    build:
      context: ./astro
    container_name: astro
    ports:
      - "9090:3000"
    env_file:
      - ./astro/.env
    command: npm start

步骤 5:从 WordPress 导入文章和图片

为了将 WordPress 的文章和图片导入 MongoDB,可以使用 WordPress 的导出工具生成 XML 文件,然后编写脚本解析并导入。

1. 导出 WordPress 数据

在 WordPress 管理后台:

  • 转到 工具 > 导出
  • 选择 所有内容,生成一个 XML 文件并下载。

2. 编写导入脚本

创建一个 Node.js 脚本解析 WordPress 的 XML 并导入到 MongoDB,同时将图片上传到 MinIO。

astro/scripts/importWordPress.js

import { MongoClient } from "mongodb";
import fs from "fs";
import { parseStringPromise } from "xml2js";
import AWS from "aws-sdk";

const MONGO_URI = process.env.MONGO_URI || "mongodb+srv://astro-user:[email protected]/blog?retryWrites=true&w=majority";
const S3_ENDPOINT = process.env.S3_ENDPOINT;
const S3_BUCKET = process.env.S3_BUCKET;
const S3_ACCESS_KEY = process.env.S3_ACCESS_KEY;
const S3_SECRET_KEY = process.env.S3_SECRET_KEY;

const s3 = new AWS.S3({
  endpoint: S3_ENDPOINT,
  accessKeyId: S3_ACCESS_KEY,
  secretAccessKey: S3_SECRET_KEY,
  s3ForcePathStyle: true,
});

async function uploadImageToS3(imageUrl) {
  const response = await fetch(imageUrl);
  const imageData = await response.buffer();

  const fileName = imageUrl.split("/").pop();
  const uploadParams = {
    Bucket: S3_BUCKET,
    Key: fileName,
    Body: imageData,
  };

  const uploadResult = await s3.upload(uploadParams).promise();
  return uploadResult.Location; // 返回 S3 存储的图片 URL
}

async function importWordPress(filePath) {
  const xmlData = fs.readFileSync(filePath, "utf-8");
  const jsonData = await parseStringPromise(xmlData);

  const posts = jsonData.rss.channel[0].item.map(async (item) => {
    const content = item["content:encoded"][0];
    const imageUrls = Array.from(content.matchAll(/<img src=\"(.*?)\"/g)).map(match => match[1]);

    const uploadedImages = await Promise.all(
      imageUrls.map(async (url) => {
        try {
          return await uploadImageToS3(url);
        } catch (err) {
          console.error(`上传图片失败:${url}`, err);
          return url; // 保留原始图片地址
        }
      })
    );

    let updatedContent = content;
    imageUrls.forEach((url, index) => {
      updatedContent = updatedContent.replace(url, uploadedImages[index]);
    });

    return {
      title: item.title[0],
      content: updatedContent,
      categories: item.category ? item.category.map((cat) => cat._) : [],
      pubDate: new Date(item.pubDate[0]),
    };
  });

  const resolvedPosts = await Promise.all(posts);

  const client = new MongoClient(MONGO_URI);
  await client.connect();
  const db = client.db("blog");

  await db.collection("posts").insertMany(resolvedPosts);
  console.log(`成功导入 ${resolvedPosts.length} 篇文章!`);
  await client.close();
}

const filePath = process.argv[2];
if (!filePath) {
  console.error("请提供 WordPress 导出的 XML 文件路径。");
  process.exit(1);
}

importWordPress(filePath).catch((err) => {
  console.error("导入失败:", err);
});

3. 运行导入脚本

在终端运行以下命令:

node scripts/importWordPress.js /path/to/wordpress-export.xml

4. 图片处理

  • 确保 MinIO 的连接信息已正确配置。
  • 将图片存储后的新地址替换文章中的旧地址。

步骤 6:验证部署

  1. 启动服务:
    docker-compose up -d
    
  2. 确保文章和图片已经成功导入到 MongoDB。
  3. 在浏览器访问 http://<NAS_IP>:9090,验证是否能够正常显示博客文章。

附加说明

  • MongoDB Atlas 数据库名:确保连接字符串中的 blog 对应的是 Atlas 集群中实际存在的数据库名。
  • 性能优化:对于高流量站点,可以启用 Atlas 的付费层,提供更强的读写性能。
  • 安全性:在生产环境中限制 IP 访问,仅允许服务器的 IP 地址访问数据库。

如果有更多需求,例如复杂查询或动态内容扩展,可以进一步调整数据库结构!