Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to run Mongoose inside next.js api?

I'm building a website for my sister so that she can sell her art. I am using Next.js to set everything up. The website renders the artwork by grabbing an array from a database and mapping through it.

Two Example objects

  {
    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,
    },
  }
}

The problem I am running into is that when I try to use mongoose in the api/get-artwork. It will only render the page once and once it is refreshed it will break I believe do to the fact the Schema and Model get redone.

pages/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
};
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);
  }
});

};

So to try to fix this I decided to use the native MongoDB driver. Like this.

/pages/api/get-artwork/

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);
};

This works for the most part but occasionally the array will not be returned. I think this is because the page is loading before the mongodb part finishes? So I guess my question is how do I make 100% sure that it loads the art correctly every time whether that be using mongoose or the native driver.

Thanks!

like image 406
Montusker Avatar asked Nov 28 '22 04:11

Montusker


1 Answers

The Next.js team has a good set of example code, which they add to regularly, one of them being Next.js with MongoDB and Mongoose. Check it out, https://github.com/vercel/next.js/tree/canary/examples/with-mongodb-mongoose, and hope this helps if you're still searching for solutions.

like image 88
Manny Avatar answered Dec 04 '22 07:12

Manny