Error while Uploading Image to Mongodb using Gridfs and Graphql - mongodb

Im trying to upload an image to mogodb using graphql and gridfs. When trying to do i'm facing a error :
" JSON Parse error: Unexpected identifier "This" "
I'm not sure what I've done wrong in the code.
Can anyone help me figure out where I've gone wrong in the implementation
This is the part for uploading Image
const selectProfilePic = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [2, 3],
quality: 1,
});
handleImagePicked(result);
};
const handleImagePicked = async (result: ImagePicker.ImagePickerResult) => {
try {
if (result.cancelled) {
alert("Upload cancelled");
return;
} else {
console.log("In HERE ::: 76");
const lastIndex = result.uri.lastIndexOf("/") + 1;
console.log(result);
const file = new ReactNativeFile({
uri: result.uri,
name: result.uri.substring(lastIndex),
type: "image/png",
});
setAvatar(result.uri);
console.log(file); // This result is getting printed.
await singleUpload({ // I think the Upload function is not getting called.
variables: {
file,
},
});
}
} catch (e) {
console.log(e);
alert("Upload failed");
}
};
Resolver Function
singleUpload: async (_, { file }, context) => {
const {db, user, hhhhhh, gfs} = context;
console.log(gfs);
const res = uploadFn({ file },gfs);
console.log(res);
Apollo.tsx File
const uploadLink = createUploadLink({
uri: CLIENT_HTTP_URI,
});
// splitLink is defined here
export const client = new ApolloClient({
link: ApolloLink.from([authLink, splitLink]),
cache: new InMemoryCache(),
});
Have created StorageEngine.js File with this code
const storage = new GridFsStorage({
url: DB_URI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if(err) { return reject(err); }
const fileName = buf.toString('hex') + path.extname(file.originalname);
const fileInfo = {
fileName,
bucketName: 'uploads'
};
resolve(fileInfo);
});
});
}
});
const upload = multer({storage});
const uploadFn = async ({file}, bucket) => {
console.log(file);
const { createReadStream, name, type, encoding } = await file;
const uploadStream = bucket.openUploadStream(name, {
contentType: type
});
// console.log(uploadStream);
return new Promise((resolve, reject) => {
createReadStream()
.pipe(uploadStream)
.on('error', reject)
.on('finish', () => {
console.log(uploadStream.id);
resolve(uploadStream.id);
});
});
}

Related

Mongo DB Runtime Error because of connection is closed too early

I had the same issue with the below question, and the answer(adding setTimeout()) worked for me.
MongoRuntimeError: Connection pool closed
But I can't find more information about this issue on any other documents, Youtube video, or MongoDB Guide. All of them close the connection without setTimeout function. Am I missing something? or if there is a better way to close the connection. Please advise.
const { MongoClient } = require("mongodb");
const url =
"mongodb+srv://USERNAME:PASSWORD#cluster0.feify.mongodb.net/products_test?retryWrites=true&w=majority";
const createProduct = async (req, res, next) => {
const newProduct = {
name: req.body.name,
price: req.body.price,
};
const client = new MongoClient(url);
try {
await client.connect();
const db = client.db();
const result = db.collection("products").insertOne(newProduct);
} catch (error) {
return res.json({ message: "Could not store data." });
}
setTimeout(() => {
client.close();
}, 1500);
res.json(newProduct);
};
const getProducts = async (req, res, next) => {};
exports.createProduct = createProduct;
exports.getProducts = getProducts;
Thank you
You should await the insertOne function:
const { MongoClient } = require("mongodb");
const url =
"mongodb+srv://USERNAME:PASSWORD#cluster0.feify.mongodb.net/products_test?retryWrites=true&w=majority";
const createProduct = async (req, res, next) => {
const newProduct = {
name: req.body.name,
price: req.body.price,
};
const client = new MongoClient(url);
try {
await client.connect();
const db = client.db();
const collection = db.collection("products");
const result = await collection.insertOne(newProduct);
} catch (error) {
return res.json({ message: "Could not store data." });
}
client.close();
res.json(newProduct);
};
const getProducts = async (req, res, next) => {};
exports.createProduct = createProduct;
exports.getProducts = getProducts;

upload and display images from cloudinary in nextjs + mongodb

(real estate nextjs application)
cannot send data with image URL to MongoDB and make a new property the API working Well,
and the MongoDB is connected i think the problem with the UI page i'm using formik for
form control , axios for API data fetching, cloudinary for images storing.
const [image, setImage] = useState([]);
const [property, setProperty] = useState(initialValues);
const { title, price, description, rentFrequency, rooms, baths, area, agency, purpose, furnishingStatus, amenities, city, garage, address, email, contact } = property;
console.log(property);
const handleOnChange = (e) => {
setProperty({ ...property, [e.target.name]: e.target.value });
};
const handleUploadInput = async (e) => {
const files = [...e.target.files];
const formData = new FormData();
for (let file of files) {
formData.append("file", file);
}
formData.append('upload_preset', 'my-uploads');
const res = await fetch(
"https://api.cloudinary.com/v1_1/shadow007/image/upload",
{
method: "POST",
body: formData,
}
);
const data = await res.json();
setImage([...image, data.secure_url]);
setProperty({ ...property, images: image }); // Maybe Im missing something around here
};
const handleOnSubmit = async (e) => {
e.preventDefault();
await createProperty();
};
// const validate = () => {
// if(!title || !price || !description || !content) return
// }
const createProperty = async () => {
try {
const res = await fetch("http://localhost:3000/api/properties", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(property),
});
const data = await res.json();
console.log(data);
} catch (err) {
console.log(err);
}

Nexjs + SWR: API resolved without sending a response for /api/projects/<slug>, this may result in stalled requests

Since on first render I was not able to get the router.query I am passing the params from getServerSideProps as follows:
export async function getServerSideProps(context) {
return {
props: { params: context.params },
};
}
Then in the function am trying to do the API call but am getting the API stalled error
API resolved without sending a response for
/api/projects/nichole_robel23, this may result in stalled requests.
This is my code:
export default function Project({ params }) {
const { slug } = params;
let [projectData, setProjectData] = useState([]);
let [loading, setLoading] = useState(true);
const { data } = useSWR('http://localhost:3000/api/projects/' + slug);
useEffect(() => {
if (data) {
setProjectData(data.data.project);
setLoading(false);
}
}, [data]);
......
I have global SWRCofig as follows
<SWRConfig value={{ fetcher: (url) => axios(url).then(r => r.data) }}>
<Layout>
<Component {...pageProps} />
</Layout>
</SWRConfig>
Any way to solve the problem?
You are missing your fetcher–the function that accepts the key of SWR and returns the data, so the API is not being called.
You are also not returning a response correctly from the API–this is most likely a case of not waiting for a promise/async to be fulfilled correctly.
CLIENT
const fetcher = (...args) => fetch(...args).then((res) => res.json());
export default function Home({ params }) {
const { slug } = params;
const [projectData, setProjectData] = useState([]);
const [loading, setLoading] = useState(true);
const { data } = useSWR(`http://localhost:3000/api/projects/${slug}`, fetcher);
useEffect(() => {
if (data) {
setProjectData(data);
setLoading(false);
}
}, [data]);
API
const getData = () => {
return new Promise((resolve, reject) => {
// simulate delay
setTimeout(() => {
return resolve([{ name: 'luke' }, { name: 'darth' }]);
}, 2000);
});
}
export default async (req, res) => {
// below will result in: API resolved without sending a response for /api/projects/vader, this may result in stalled requests
// getData()
// .then((data) => {
// res.status(200).json(data);
// });
// better
const data = await getData();
res.status(200).json(data);
}

FetchError: invalid json response body at http://localhost:3000/api/products/6092ca3460fc67315178f2fa reason: Unexpected token < in JSON at position 0

I am trying to fetch data from MongoDB, but apparently, it gives an error
FetchError: invalid json response body at
http://localhost:3000/api/products/6092ca3460fc67315178f2fa reason: Unexpected token < in JSON at position 0
const defaultEndpoint = 'http://localhost:3000/api/products/';
export const getStaticPaths = async () => {
const res = await fetch(defaultEndpoint);
const data = await res.json();
const paths = data.map (product => {
return {
params: { id: product._id.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch ('http://localhost:3000/api/products/' + id);
const data = await res.json ();
return {
props: {product: data}
}
}
const Details = ({product}) => {
return (
<div>
<h1>{product.title}</h1>
</div>
)
}
export default Details
API Endpoint which is perfectly working on http://localhost:3000/api/products
import { connectToDatabase } from "../../util/mongodb";
export default async (req, res) => {
const { db } = await connectToDatabase();
const products = await db.collection("products").find({}).toArray();
res.json(products);
};

Firebase cloud functions not waiting for forEach to complete before jumping to the next then

Been trying to copy subcollections of a collection into another collection. The code below is aimed at that, but jumps from the first then and logs out "Done" without logging out anything before.
So the question is what is not correct here?
exports = module.exports = functions.https.onRequest(async (req, res) => {
let db = admin.firestore();
try {
await db.collection("users").get().then((query) => {
return query.forEach(async (doc) => {
console.log("Here"); //This doesn't print
const polCollection = await db.collection("users").doc(doc.id).collection("xyz").get();
if (polCollection.docs.length > 0) { //This checks if any subcollections
for (const x of polCollection.docs) { //This copies them into a doc in the copy collection
db.collection("CopyUsers")
.doc(doc.id)
.set({ x : x.data() }, { merge: true });
}
}
});
})
.then(() => {
console.log("Done"); //This is the only thing that prints in the console
res.end();
})
.catch((e) => {
console.log("e", e);
res.end();
});
} catch (error) {
console.log("error", error);
res.end();
}
});
After the suggestion below, it now looks as follows:
exports = module.exports = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
const promises = [];
let count = 0;
let size = 0;
return await admin
.firestore()
.collection("testUsers")
.get()
.then((query) => {
console.log("query length:", query.size); //prints x of users
size = query.size;
query.forEach(async (doc) => {
const promise = async () => {
console.log("Here", doc.id); //This doesn't print
await admin
.firestore()
.collection("testUsers")
.doc(doc.id)
.collection("xyz")
.get()
.then(async (polCollection) => {
if (polCollection.docs.length > 0) {
for (const x of polCollection.docs) {
return await admin
.firestore()
.collection("testBackUpUsers")
.doc(doc.id)
.set(
{ xyz: x.data() },
{ merge: true }
);
}
} else {
return;
}
})
.catch((e) => console.log("error from then after get xyz", e));
};
count++;
return promises.push(promise);
});
return promises;
})
.then(async (promises) => {
if (size <= count) {
console.log("running return Promise.all(promises)", promises.length); //prints number of promises = users
return Promise.all(promises);
}
})
.catch((e) => console.log("err from the last catch", e));
});
Any thoughts?
Unfortunately the forEach iterator does not support async/await. Even if you write an await inside it will just go trough it without waiting on the execution.
I would recommend to use Promise.all. That would also execute the code in parallel and would finish faster.
If you would only change data you could also use a batch change but in your example you first get the data and then change it.
Here is an example how you could write your code:
exports = module.exports = functions.https.onRequest(async (req, res) => {
let db = admin.firestore();
const promises = [];
try {
const query = await db.collection("users").get();
query.forEach((doc) => {
console.log("doc", doc);
const promise = async () => {
console.log("Here", doc.id); //This doesn't print
const polCollection = await db
.collection("users")
.doc(doc.id)
.collection("xyz")
.get();
if (polCollection.docs.length > 0) {
//This checks if any subcollections
for (const x of polCollection.docs) {
//This copies them into a doc in the copy collection
await db
.collection("CopyUsers")
.doc(doc.id)
.set({ x: x.data() }, { merge: true });
}
}
};
promises.push(promise);
});
console.log("promises", promises);
await Promise.all(promises);
console.log("Done");
res.end();
} catch (error) {
console.log("error", error);
res.end();
}
});