mongodb 是否可以在next.js api中运行Mongoose?

k0pti3hp  于 2022-11-22  发布在  Go
关注(0)|答案(5)|浏览(150)

我正在为我的妹妹建立一个网站,这样她就可以出售她的艺术品。我使用Next.js来设置一切。网站通过从数据库中获取一个数组并通过它进行Map来渲染艺术品。
两个示例对象

{
    id: 8,
    path: "images/IMG_0008.jpg",
    size: "9x12x.75",
    price: "55",
    sold: false
  }
  {
    id: 9,
    path: "images/IMG_0009.jpg",
    size: "9x12x.75",
    price: "55",
    sold: false
}

pages/Shop.js

import Card from "../Components/Card";
import fetch from 'node-fetch'
import Layout from "../components/Layout";

function createCard(work) {
  return (
    <Card
      key={work.id}
      id={work.id}
      path={work.path}
      size={work.size}
      price={work.price}
      sold={work.sold}
    />
  );
}

export default function Shop({artwork}) {
  return (
    <Layout title="Shop">
      <p>This is the Shop page</p>

        {artwork.map(createCard)}
    </Layout>
  );
}

export async function getStaticProps() {
  const res = await fetch('http://localhost:3000/api/get-artwork')
  const artwork = await res.json()

  return {
    props: {
      artwork,
    },
  }
}

我遇到的问题是,当我尝试在api/get-artwork中使用mongoose时,它只会呈现页面一次,一旦刷新,它就会中断,我相信这是因为架构和模型被重做了。
pages/api/获取图片.js/

const mongoose = require("mongoose");


mongoose.connect('mongodb://localhost:27017/ArtDB', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false
});

const itemsSchema = {
  id: String,
  description: String,
  path: String,
  size: String,
  price: Number,
  sold: Boolean
};
const Art = mongoose.model("Art", itemsSchema);

export default (req, res) => {
  Art.find({sold: false}, (err, foundItems)=> {
  if (err) {
    console.log(err);
  } else {
    console.log(foundItems);
    res.status(200).json(foundItems);
  }
});

};

所以为了解决这个问题,我决定使用原生的MongoDB驱动程序。就像这样。
/pages/api/获取图片/

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');

// Connection URL
const url = 'mongodb://localhost:27017';

// Database Name
const dbName = 'ArtDB';

// Create a new MongoClient
const client = new MongoClient(url, {useUnifiedTopology: true});

let foundDocuments = ["Please Refresh"];

const findDocuments = function(db, callback) {
  // Get the documents collection
  const collection = db.collection('arts');
  // Find some documents
  collection.find({}).toArray(function(err, arts) {
    assert.equal(err, null);
    foundDocuments = arts;
    callback(arts);
  });
}

// Use connect method to connect to the Server
client.connect(function(err) {
  assert.equal(null, err);

  const db = client.db(dbName);

  findDocuments(db, function() {
     client.close();
   });

});
export default (req, res) => {
  res.send(foundDocuments);
};

这在大多数情况下都有效,但有时数组不会被返回。我想这是因为页面在mongodb部分完成之前加载了?所以我想我的问题是,我如何100%确保它每次都正确加载艺术作品,无论是使用mongoose还是本机驱动程序。
谢谢你!

20jt8wwn

20jt8wwn1#

Next.js团队有一组很好的示例代码,他们定期添加这些代码,其中之一是带有MongoDB和Mongoose的Next.js。如果您还在寻找解决方案,请查看https://github.com/vercel/next.js/tree/canary/examples/with-mongodb-mongoose,希望这对您有所帮助。

eulz3vhy

eulz3vhy2#

一个更完整的答案可能会有帮助。
我会建议使用next-connect库来使这变得简单一点,而不是那么多余。
注意到开发中不必要的重新连接,所以我绑定到节点中的全局this属性。也许这不是必需的,但这就是我注意到的。可能在开发过程中绑定到热重载。
这是一个很长的帖子,但并不像看起来那么复杂,如果你有问题,请评论。

创建中间件帮助程序:

import mongoose from 'mongoose';

// Get your connection string from .env.local

const MONGODB_CONN_STR = process.env.MONGODB_CONN_STR;

const databaseMiddleware = async (req, res, next) => {

  try {

    if (!global.mongoose) {

      global.mongoose = await mongoose.connect(MONGODB_CONN_STR, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useFindAndModify: false,
      });

    }

  }
  catch (ex) {
    console.error(ex);
  }

  // You could extend the NextRequest interface 
  // with the mongoose instance as well if you wish.
  // req.mongoose = global.mongoose;

  return next();

};

export default databaseMiddleware;

创建模型:

通常,此处的路径可能是src/models/app.ts

import mongoose, { Schema } from 'mongoose';

const MODEL_NAME = 'App';

const schema = new Schema({
  name: String
});

const Model = mongoose.models[MODEL_NAME] || mongoose.model(MODEL_NAME, schema);

export default Model;

实施下一个连接:

通常,我会将它放在src/middleware/index.ts这样的路径中(如果不使用Typescript,则放在index.js中)。
注意:这里的...middleware只允许您(见下文)在创建这里的处理程序时动态传入其他中间件。
这是非常有用的,因为我们的处理程序创建器可以有日志和其他有用的中间件,所以它在每个页面/api文件中不是那么多余。

export function createHandler(...middleware) {

  return  nextConnect().use(databaseMiddleware, ...middleware);

}

用于Api途径:

把这些放在一起,我们现在可以轻松地使用我们的应用程序模型

import createHandler from 'path/to/above/createHandler';
import App from 'path/to/above/model/app';

// again you can pass in middleware here
// maybe you have some permissions middleware???
const handler = createHandler(); 

handler.get(async (req, res) => {
  
  // Do something with App
  const apps = await App.find().exec();

  res.json(apps);

});

export default handler;
sirbozc5

sirbozc53#

在**页/api/get-artwork.js/**中

const mongoose = require("mongoose");

mongoose.connect("mongodb://localhost:27017/ArtDB", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false,
});

const itemsSchema = {
  id: String,
  description: String,
  path: String,
  size: String,
  price: Number,
  sold: Boolean,
};

let Art;

try {
  // Trying to get the existing model to avoid OverwriteModelError
  Art = mongoose.model("Art");
} catch {
  Art = mongoose.model("Art", itemsSchema);
}

export default (req, res) => {
  Art.find({ sold: false }, (err, foundItems) => {
    if (err) {
      console.log(err);
    } else {
      console.log(foundItems);
      res.status(200).json(foundItems);
    }
  });
};

对我来说很好。

31moq8wy

31moq8wy4#

当我们在express.js中使用mongoose时,我们连接到mongodb并运行一次代码,但在next.js中,每次需要连接到mongodb时,我们都必须运行连接代码。

连接到mongodb

import mongoose from "mongoose";

const dbConnect = () => {
  if (mongoose.connection.readyState >= 1) {
    // if it is not ready yet return
    return;
  }

  mongoose
    .connect(process.env.DB_LOCAL_URI, {
      //****** since  mongoose 6, we dont need those******
      //   useNewUrlParser: true,
      //   useUnifiedTopology: true,
      //   useFindAndModify: false,
      //   useCreateIndex: true,
    })
    .catch((err) => console.log(err))
    .then((con) => console.log("connected to db"));
};

export default dbConnect;

在下一个API中使用它

在运行处理程序代码之前,需要先连接

import dbConnect from "../../../config/dbConnect";

dbConnect();

... then write handler code
vwkv1x7d

vwkv1x7d5#

简洁的OO方法

受@Blujedis答案的启发,这就是我最终得到的答案。

/* /api/util/handler.js */

import nextConnect from "next-connect";
import mongoose from "mongoose";

export class Handler {

    static dbConnection = null

    static dbMiddleware = async (req, res, next) => {
        try {
            Handler.dbConnection ||= await mongoose.connect(process.env.MONGO_URL)
            next()
        } catch (err) {
            console.error(err);
            next(err)
        }
    }

    constructor(...middleware) {
        return nextConnect().use(Handler.dbMiddleware, ...middleware);
    }
}

示例处理程序:

/* /api/people.js */

import { Handler } from "./util/handler"
import { Person } from "./models/person"

export default
    new Handler()
        .get(async (req, res) => {
            const people = await Person.find({})
            return res.status(200).json(people)
        })

相关问题