MongoClient's findOne() never resolves on Electron, even when collection is populated - javascript

I'm working on making a web app with Electron and I successfully connected to a Mongo DB Atlas database and I'm able to send information to it. However, I seem to be unable to retrieve it. The first snippet of code that I included is how I connected to the database.
MongoClient.connect(URI, (err, client) => {
if (err){
console.log("Something unexpected happened connecting to MongoDB Atlas...");
}
console.log("Connected to MongoDB Atlas...");
currentDatabase = client.db('JukeBox-Jam-DB'); /* currentDatabase contains a Db */
});
Then, this second snippet is how I've been writing to the database, which seems to work perfectly fine.
ipc.on('addUserToDatabase', (event, currentUser) => {
const myOptions = {
type: 'info',
buttons: ['Continue'],
defaultId: 0,
title: 'Success',
message: 'Your account has been created.'
};
dialog.showMessageBox(mainWindow, myOptions);
currentCollection = currentDatabase.collection('UsersInformation');
currentCollection.insertOne(currentUser);
});
Lastly, this is the code that I've been trying to use to retrieve information from the database. I don't see where I could be making a mistake so that it is not working for retrieving, but yes for writing. From my understanding findOne() when passed without parameters should simply return a Promise that resolves to the first entry that matches the query that is passed to it. If a query is not provided then it will resolve to the item that was put in the database first. If there's no entry that matches the query, then it should resolve to null. Any ideas why this isn't working?
ipc.on('checkUsernameRegistration', (event) => {
currentCollection = currentDatabase.collection('UsersInformation');
let myDocument = currentCollection.findOne(); /* I don't understand why this isn't working! */
console.log(myDocument); /* This prints Promise { <pending> } */
if (myDocument !== null){ /* If myDocument is not null, that means that that there is already someone with that username in the DB. */
}
});
Thanks to everyone that is attempting to help me! I've been stuck in this for several hours now.

Try using async/await :
ipc.on('checkUsernameRegistration', async (event) => {
currentCollection = currentDatabase.collection('UsersInformation');
let myDocument = await currentCollection.findOne({ _id: value });
if (myDocument !== null){
console.log(myDocument);
}
});
or, you need to pass a callback, like this:
currentCollection.findOne({ country: 'Croatia' }, function (err, doc) {
if (err) console.error(err);
console.log(doc);
});
This happens because queries are not promises. Actually, I recommend you to study the difference between async and sync code in node.js. Just to understand where the callback should be passed to function, and where you can simply write await Model.method({ options }).

Related

how to get a particular user data from MongoDB in node.js

I'm doing a project on an e-commerce website. here I'm with a problem.
I have used the get method to retrieve user data from MongoDB
I have passed the correct parameters and the statement UserId:req.params.userId has been satisfied where we can see in the nodejs terminal.
I'm looking to get only particular user data with UserId === UserId. But in my result, all the user's data is popping up.
Im trying this but the solution im getting is all the users data
i have tried using findOne() but the result is this 635ea7e5e931e12c9f851dd3 user details. where the parameter is 63a8a0f77addf42592eed1e5. where im expecting to get the only user which im passing in parameter.
router.get("/find/:userId", verifyTokenAndAuthorization, async (req, res) => {
try {
const cart = await Cart.find(
{userId : req.params.userId});
console.log("parameter: "+req.params.userId)
return res.status(200).json(cart);
} catch (err) {
res.status(500).json(err);
}
The req.params userId is '63a8a0f77addf42592eed1e5'. i need only this. but it is popping up all the users data.
Node.js terminal showing the parameter is same with userId
Postman showing the response of all users present in the DB but i need only the user details which i had passed in the parameter
Here the mongoDB find method returns all data in the collection, irrespective of the parameters that we pass in to it. Instead try using the findOne method for that collection. So the code with correction will be as follows:
router.get("/find/:userId", verifyTokenAndAuthorization, async (req, res) => {
try {
const cart = await Cart.findOne(
{userId : req.params.userId});
console.log("parameter: "+req.params.userId)
return res.status(200).json(cart);
} catch (err) {
res.status(500).json(err);
}
You can read more about the method at MongoDB Manual.
I had found the solution for my problem i.e I have used filter method at (res(200).json(cart.filter(((user)=>user.UserId === req.params.userId))
This means
Using filter method UserId in my model === to the parameters userId
router.get("/find/:userId", verifyTokenAndAuthorization, async (req, res) => {
try {
const cart = await Cart.find(
{userId : req.params.userId});
console.log("parameter: "+req.params.userId)
res.status(200).json(cart.filter((user)=>user.UserId === req.params.userId));
console.log(cart.filter((user)=>user.UserId === req.params.userId))
} catch (err) {
res.status(500).json(err);
}
});

Error while deleting a value of element in mongoDB array using filter function?

I tried to find the solutions over here but unable to get success while using $pull as the array values I have does not contain `mongo_id'.
So the scenario is that , I am trying to delete the specific comment of the particular user which I am passing through query params. M
My mongo data looks like this:
Now I am making API Delete request like this : http://localhost:8000/api/articles/learn-react/delete-comment?q=1 on my localhost .
ANd finally my code looks like this:
import express from "express";
import bodyParser from "body-parser";
import { MongoClient } from "MongoDB";
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect(
"mongodb://localhost:27017",
{ useNewUrlParser: true },
{ useUnifiedTopology: true }
);
const db = client.db("my-blog");
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: "Error connecting to db", error });
}
};
app.delete("/api/articles/:name/delete-comment", (req, res) => {
const articleName = req.params.name;
const commentIndex = req.query.q;
withDB(async(db) => {
try{
const articleInfo = await db.collection('articles').findOne({name:articleName});
let articleAllComment = articleInfo.comments;
console.log("before =",articleAllComment)
const commentToBeDeleted = articleInfo.comments[commentIndex];
//console.log(commentToBeDeleted)
// articleAllComment.update({
// $pull: { 'comments':{username: commentToBeDeleted.username }}
// });
articleAllComment = articleAllComment.filter( (item) => item != commentToBeDeleted );
await articleAllComment.save();
console.log("after - ",articleAllComment);
//yaha per index chahiye per kaise milega pta nhi?
//articleInfo.comments = gives artcle comment
res.status(200).send(articleAllComment);
}
catch(err)
{
res.status(500).send("Error occurred")
}
},res);
});
I have used the filter function but it is not showing any error in terminal but also getting 500 status at postman.
Unable to figure out the error?
I believe you'll find a good answer here:
https://stackoverflow.com/a/4588909/9951599
Something to consider...
You can use MongoDB's built-in projection methods to simplify your code.
https://docs.mongodb.com/manual/reference/operator/projection/positional/#mongodb-projection-proj.-
By assigning a "unique ID" to each of your comments, you can find/modify the comment quickly using an update command instead of pulling out the comment by order in the array. This is more efficient, and much simpler. Plus, multiple read/writes at once won't interfere with this logic during busy times, ensuring that you're always deleting the right comment.
Solution #1: The recommended way, with atomic operators
Here is how you can let MongoDB pull it for you if you give each of your comments an ID.
await db.collection('articles').updateOne({ name:articleName },
{
$pull:{ "comments.id":commentID }
});
// Or
await db.collection('articles').updateOne({ name:articleName, "comments.id":commentID },
{
$unset:{ "comments.$":0 }
});
Solution #2 - Not recommended
Alternatively, you could remove it by index:
// I'm using "3" here staticly, put the index of your comment there instead.
db.collection('articles').updateOne({ name:articleName }, {
$unset : { "comments.3":0 }
})
I do not know why your filter is erroring, but I would recommend bypassing the filter altogether and try to utilize MongoDB's atomic system for you.

How to return value of both of the consecutive async functions in JS?

I've recently started with web development, and am a novice in JavaScript.
I'm currently working on a Blog Project and using Firebase as the backend, and Firestore as the Database.
PROJECT-
using the following project structure
Firestore DB ->
-Posts
-post1
-post2
-post3
...
-authors
-author1
-author2
..
-subscribers
...
I'm using this function to retrieve my posts from Firestore.
app.get('/:id', (req, res) => {
const id = req.params.id;
async function getDocument(id) {
const doc = await db.collection('Posts').doc(id).get();
if (!doc.exists) {
console.log('No such document!');
} else {
return doc.data();
}
}
getDocument(id).then(function (data) {
res.render('post',{ articleInfo:data} );
// that send back an object containing post details
})
Now, from the JSON I get from the above function, I want to use the value of "Author" to get the author's details from the another collection(run another async function),
and then send this data along with the data from previous function(used to get post details) together in res.render()
For example
I make a get request for a post and get back it's details. Inside which get the author's name "{..,"author : mike-ross",..} " .
Now, after .then, I use this value to run another async function get this author's JSON from the Authors collection. and pass the result from both the functions together in res.render() to get diplayed on the page.
You could have one async function that does both calls and returns an object with both results:
async function getDocWithDetails (id) {
const doc = await getDocument(id);
const authorInfo = await getAuthorInfo(doc.author);
return {
doc: doc.data(),
authorInfo: doc.data()
}
}
getDocWithDetails(id).then((data) => {
res.render('post', data) // has data.doc and data.authorInfo
});
Just go for it, same way you did the first half :-)
In general (at least at my work projects), it's good practice to setup multiple getters for each collection or one main getter where the collection is a secondary argument.
Here's the second variant with dynamic variant (but the first one is just as valid). Especially if you're not using typescript or flowtype to typecheck what you're passing, then it's more prone to unexpected errors by passing incorrect param, I'm just lazy to write the similar function in the answer twice.
const getDocumentById = async (id, collection) => {
const doc = await db.collection(collection).doc(id).get()
if (!doc.exists) {
throw Error(`Doc with id "${id}" doesn't exist on collection "${collection}"`)
}
return doc.data()
}
Now that we have our generic getter setup, you just need to create a function that fetches both.
As a precursor, I have taken some creative liberties with the answer, since the question is missing some cruicial info about documents.
At the very least (and if you don't you should, it's good firebase practice) I presume you have a link to the authorId inside Posts document.
Posts
-> post
-> id
-> authorId
-> some_other_fields
Authors
-> author
-> id
-> some_other_fields
With the following structure in mind, your answer will look something like this:
const getAuthorByPostId = async (id) => {
try {
const post = await getDocumentById(id, 'Posts')
const { authorId } = post
const author = await getDocumentById(authorId, 'Authors')
// I'm not sure how your res is structured, but could look something like this
res.render('page', { articleInfo: post, authorInfo: author })
} catch (error) {
console.error(error.message)
}
// in case it was unable to fetch data
return null
}

Editing a mongoDB item not updating but not receiving an error

I am desperate for some help with an issue I am having updating an item in a mongoDB database. I am creating a simple note application using nodeJS and I have set it up to add notes and remove notes to and from the database with no issues.
When I try to edit notes however, the update does not persist to the database. I dont get an error back and when I console.log the result it displays the correct data but just wont seem to push it to the data base. I have been using mongoose and findByIdAndUpdate. Here is the JavaScript code for my update route
app.put("/:id", (req, res) => {
Note.findByIdAndUpdate(req.params.id, req.body.note, (err, updatedNote) => {
if(err) {
console.log(err);
} else {
res.redirect(`/${req.params.id}`);
console.log(req.params.id);
console.log(req.body.note);
console.log("note updated");
}
});
});
As I mentioned, I dont get any error and the console.logs return the correct id and updated content. All my routes take me to the place so I don't believe there is an issue with them. Any help would be greatly appreciated. I can also provide more code if needed
Thanks in advance
Will
When updating in MongoDB, you have to reference the field you are trying to update. Your code should look like this
app.put("/:id", (req, res) => {
Note.findByIdAndUpdate(req.params.id, {text: req.body.note}, (err, updatedNote) => {
if(err) {
console.log(err);
} else {
res.redirect(`/${req.params.id}`);
console.log(req.params.id);
console.log(req.body.note);
console.log("note updated");
}
});
});
PS: I am hoping the field in the DB model is called text
To make the code look sexier, you can switch it to Async/Await
app.put("/:id", async (req, res) => {
let updatedNote = await Note.findByIdAndUpdate(req.params.id, {text:
req.body.note}, {new: true}).catch(err => console.log(err))
res.redirect(`/${req.params.id}`);
console.log(req.params.id);
console.log(req.body.note);
console.log("note updated");
});
That updatedNote is the same as before the update is expected behavior – see the mongooe docs:
By default, findOneAndUpdate() returns the document as it was before
update was applied. If you set new: true, findOneAndUpdate() will
instead give you the object after update was applied.
This does not mean the update did not take place.

Post Multiple Objects Inside Express Route

I would like to post multiple objects to my mongo database inside of an express route. Currently, everything is working fine when I do it as a single object (ie ONE casino), please see below, but instead of doing this a million times over, can someone help me do it as one giant data dump so I can post ALL my casinos?
Here is my route that works fine for posting a single object:
router.post('/post', async (req, res) => {
console.log(req.body);
const casinoD = new Casino({
casino: req.body.casino,
table_and_other: req.body.table_and_other,
poker: req.body.poker,
slot_machines: req.body.slot_machines,
total_gaming_win: req.body.total_gaming_win,
year: req.body.year,
month: req.body.month,
combined_date: req.body.combined_date
})
try {
const newCasino = await casinoD.save()
res.status(201).json(newCasino)
} catch (err) {
res.status(400).json({ message: err.message})
}
})
I also understand mongoimport is a better way to do this - however that had its own issues in of itself.
Thanks
Like #JDunken said, you can iterate over the POST body as an array and insert in bulk. You'll want to use
insertMany for speed. To insert millions of records, you will probably want to put a sane limit on the number of records per request, and send API requests in batches. Validation is optional, as Mongoose will run validation according to the schema. It depends on how you want to handle validation errors. Make sure to read up on the ordered and rawResult options for that as well.
router.post('/post', async (req, res) => {
// you should sanity check that req.body is an array first, depending on how robust you want error handling to be
const casinos = req.body.filter(input => isValid(input));
try {
const insertedCasinos = await CasinoModel.insertMany(casinos, { ordered: false });
res.status(201).json(insertedCasinos)
} catch (err) {
res.status(400).json({ message: err.message})
}
})
const isValid(input) {
let valid = true;
// implement input validation
return valid;
}

Categories