how to retrieve/download image from mongoDB using GridFS in Next.js - mongodb

I have uploaded a few images in MongoDB but cannot retrieve the images. I'm new to Next js, can anyone explain how I can make a "/api/retrieve?fileName='...'" get API to retrieve images from the database. The handler is being executed first then the db connection message is showing.
import nc from "next-connect";
import mongoose from "mongoose";
import Grid from "gridfs-stream";
import { GridFsStorage } from "multer-gridfs-storage";
export const config = {
api: {
bodyParser: false,
},
};
Grid.mongo = mongoose.mongo;
let gfs;
const conn = mongoose.createConnection(
process.env.mongoURI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
},
(err) => {
if (err) {
console.err("file DB connection error", err);
process.exit();
}
console.log("file DB connected!");
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection("images");
}
);
export default async function handler(req, res) {
if (req.method === "GET") {
console.log("request query: ", req.query);
try {
const file = await gfs.files.findOne({ filename: req.query.filename });
const readStream = gfs.createReadStream(file.filename);
readStream.pipe(res);
} catch (error) {
res.send("not found");
}
}
}
Thanks in advance.

Related

MissingSchemaError: Schema hasn't been registered for model in nextjs13

error - MissingSchemaError: Schema hasn't been registered for model "post".
Use mongoose.model(name, schema)
at Mongoose.model (/Users/mac/Practice/portfolio_projects/ai-image-generation/node_modules/mongoose/lib/index.js:549:13)
at eval (webpack-internal:///(api)/./src/lib/mongodb/models/post.ts:34:52)
at (api)/./src/lib/mongodb/models/post.ts (/Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/pages/api/post.js:62:1)
at webpack_require (/Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/webpack-api-runtime.js:33:42)
at eval (webpack-internal:///(api)/./src/pages/api/post.ts:9:82)
at (api)/./src/pages/api/post.ts (/Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/pages/api/post.js:82:1)
at webpack_require (/Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/webpack-api-runtime.js:33:42)
at webpack_exec (/Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/pages/api/post.js:92:39)
at /Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/pages/api/post.js:93:28
at Object. (/Users/mac/Practice/portfolio_projects/ai-image-generation/.next/server/pages/api/post.js:96:3)
for db connection
import { MongoClient } from "mongodb";
if (!process.env.MONGODB_URI) {
throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
}
const uri = process.env.MONGODB_URI;
const options = {};
let client;
let clientPromise: Promise<MongoClient>;
if (process.env.NODE_ENV === "development") {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;
**Post.tsx **
import * as mongoose from "mongoose";
import Joi from "joi";
type post = {
name: string;
prompt: string;
photo: string;
};
const PostSchema = new mongoose.Schema({
name: { type: String, required: true },
prompt: { type: String, required: true },
photo: { type: String, required: true },
});
function validatePost(data: post) {
const schema = Joi.object({
name: Joi.string().min(1).max(100).required(),
prompt: Joi.string().min(2).required(),
photo: Joi.string().min(0).required(),
});
return schema.validate(data);
}
const Post = mongoose.model("post") || mongoose.model("post", PostSchema);
export { validatePost };
export default Post;
**
Where i called post modal**
import type { NextApiRequest, NextApiResponse } from "next";
import clientPromise from "#/lib/mongodb/mongodb";
import { v2 as cloudinary } from "cloudinary";
import Post from "#/lib/mongodb/models/post";
import { validatePost } from "#/lib/mongodb/models/post";
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
export const config = {
api: {
bodyParser: {
sizeLimit: "50mb",
},
responseLimit: false,
},
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
await clientPromise;
if (req.method === "GET") {
try {
const posts = await Post.find({});
res.status(200).json({ success: true, data: posts });
} catch (err) {
res.status(500).json({
success: false,
message: "Fetching posts failed, please try again",
});
}
} else if (req.method === "POST") {
try {
const { error } = validatePost(req.body);
if (error) return res.status(400).send(error.details[0].message);
const { name, prompt, photo } = req.body;
const photoUrl = await cloudinary.uploader.upload(photo);
const post = new Post({
name,
prompt,
photo: photoUrl.url,
});
const newPost = await post.save();
res.status(200).json({ success: true, data: newPost });
} catch (err) {
res.status(500).json({
success: false,
message: "Unable to create a post, please try again",
});
}
}
}

trying to get uploads saving in MongoDB

I currently have the following code, which saves the temp file to public/files I have tried to understand the MongoDB GridFS documentation but with no success.
I am wondering how do I get the files to save inside MongoDB GridFS instead of my public/file directory
I am aware I am missing the part where I need to send the uploaded file to mongodb - this is the part I don't know how to do.
In mongodb example they say to do something like:
fs.createReadStream('./myFile').pipe(
bucket.openUploadStream('myFile', {
chunkSizeBytes: 1048576,
metadata: { field: 'myField', value: 'myValue' },
})
);
however I am not using FS or do I need to upload the file to the temp and then do the fs
import formidable from 'formidable';
import { MongoClient, ObjectId } from 'mongodb';
var Grid = require('gridfs-stream');
export const config = {
api: {
bodyParser: false,
},
};
export default async (req, res) => {
const uri = process.env.MONGODB_URI;
let client;
let clientPromise;
const options = {};
client = new MongoClient(uri, options);
clientPromise = client.connect();
const clients = await clientPromise;
const database = clients.db('AdStitchr');
var gfs = Grid(database, client);
gfs.collection('uploads');
const form = new formidable.IncomingForm();
form.uploadDir = 'public/files';
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
var file = files.file;
console.log(JSON.stringify(file));
try {
const newFile = File.create({
name: `files\${file.newFilename}.mp3`,
});
res.status(200).json({ status: 'success' });
} catch (error) {
res.send(error);
}
});
};

Socket.io, Mongodb returning undefined to frontend

I want to use socekt.io for a new project I am building. I am using socket.io for a login component and will be using socket.io in the future to update pages like a chat app. I am also using mongoose to handle my mongodb connection. I am taking in a username, and returning a password to my front end to be bcryptjs compareSync hashed. The problem I am having is that whatever is returned to the front end is undefined. When I print out what is returned to the front end, it prints out the value I am looking for though. Something is going on between the backend emitting something, and the frontend receiving something but I don't know what is it exactly. Here is my code for the back end:
const express = require('express')
const socket = require('socket.io');
const http = require('http');
const router = require('./router');
const mongoose = require('mongoose');
let Player = require('../models/player.model');
require('dotenv').config();
const PORT = process.env.PORT || 5000;
const app = express();
const server = http.createServer(app);
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, {useNewUrlParser: true, useCreateIndex: true,
useUnifiedTopology: true });
const connection = mongoose.connection;
connection.once('open',() => {
console.log('MongoDB database connection established successfully')
});
const io = socket(server);
io.on('connection', (socket) => {
console.log('We have a new connection');
socket.on('login', ({ username }, callback) => {
console.log(username);
Player.find({"username": username}, function (err, player) {
if(err) {
console.log("there has been an error"), {player: null}
}
socket.emit('id', { password: player[0]['password'].toString(), id : player[0]['_id']})
}) })})
app.use(router);
server.listen(PORT, () => console.log('Server is working'))
Here is my code for the front end:
const ENDPOINT = 'localhost:5000';
async function submitAccount (e) {
e.preventDefault();
socket.emit('login', { username });
socket.on("id", (response) => {
setPassword2(String(response['password']));
id = response['id']; console.log(id);
console.log(password2)
});
try {
if (bcrypt.compareSync(password, password2) == true) {
props.setCookie("id", id);
setAccess(true);
access2 = true;
console.log(access2)
console.log('works')
}
else {
setErrorType('Invalid Password')
setErrorMsg('There is an issue with your password. Please try again')
setOpenModal(true)
console.log(password);
console.log(password2);
}
}
catch {
setErrorType('Invalid Username')
setErrorMsg('This username does not exist. Please try another')
setOpenModal(true)
}
Thanks for the help!
When you do the socket.on, it should include the whole statement you are looking to change with the socket.io output. See below:
async function submitAccount (e) {
e.preventDefault();
socket.emit('login', { username });
socket.on("id", (response) => {
setPassword2(String(response['password']));
id = response['id']; console.log(id);
console.log(password2)
if (password2 != undefined) {
try {
if (bcrypt.compareSync(password, password2) == true) {
props.setCookie("id", id);
setAccess(true);
access2 = true;
console.log(access2)
console.log('works')
}
}

MongoDB authorization problem for command copydb

i've a problem in my nodejs mongoDB script, it look like that
const MongoClient = require('mongodb').MongoClient;
const dotenv = require('dotenv');
const test = require('assert');
dotenv.config();
const url = process.env.MONGO_URI;
async function main(){
MongoClient.connect(url, function(err, client) {
if (err) {
console.log(err);
}
else {
const adminDb = client.db().admin();
const mongoCommand = { copydb: 1, fromdb: "dbtest", todb: "newdbtest"};
adminDb.command(mongoCommand, function(commandErr, data) {
if (!commandErr) {
console.log(data);
} else {
console.log(commandErr.errmsg);
}
client.close();
});
}
});
}
main().catch(console.error);```
But when i run this script, i have an error not authorized on admin to execute command...
and i don't understand why my user from MongoDB Atlas can't perform this operation
Can you help me ?
Is that because i have a free cluster ?
Thanks in advance

How to get MongoClient object from Mongoose?

I have to get the MongoClient object from mongoose connection object, so that I can reuse for Agenda or somewhere else where I need.
db.js
// Export the mongoose instance
module.exports = () => {
mongoose.Promise = global.Promise;
try {
console.log('DBURL:', dbConfig.url);
const { url, options } = dbConfig;
mongoose
.connect(url, options)
.then(() => console.log('DB Connected'), err => console.log(err, options));
mongoose.connection.on('connected', () => {
logger.log('info', 'Mongoose default connection opened');
});
mongoose.connection.on('error', (err) => {
// logger.log('error', 'Couldn't able to connect to MongoDB', err);
// Blow system on db error
logger.log('info', 'Mongoose default connection opened');
throw err;
});
mongoose.connection.on('reconnected', () => {
logger.log('info', 'Mongo connection reconnected', arguments);
});
mongoose.connection.on('disconnecting', () => {
logger.log('error', 'Mongoose connection disconnecting', arguments);
});
mongoose.connection.on('disconnected', () => {
logger.log('error', 'Mongoose connection disconnected', arguments);
});
} catch (e) {
console.log("Couldn't connect to mongo:", e);
}
return mongoose;
};
You can get the mongoClient with getClient() method as shown in the docs: getClient()
Basically you need to do something like this
const client = mongoose.connection.getClient()
So to use it with connect-mongo for example you could just export that from your db.js then import and use where needed.
//db.js
module.exports.client = mongoose.connection.getClient()
//app.js
const { client } = require('path to file')
const store = MongoStore.create({ client })
const mongoose = require("mongoose");
let options = { //Your options };
const mongoClient = new mongoose.mongo.MongoClient(URI, options)
config = require('./configs');
mongoose = require('mongoose');
module.exports = function() {
var db = mongoose.connect(config.db, config.mongoDBOptions).then(
() => {
console.log('MongoDB connected')
},
(err) => {
console.log('MongoDB connection error',err)
}
);
require('../app/models/xxx.server.model');
require('../app/models/yyy.server.model');
return db;};
You may get MongoClient Object by following this method:
const { MongoClient, ObjectID } = require('mongodb');
function(req, res) {
(async function mongo() {
let client;
try {
client = await MongoClient.connect(url, {useNewUrlParser: true});
debug('Connected correctly to server');
const db = client.db(dbName);
}