How can use the .count() method in mongoose to count multiple collections - javascript

I have a operation that counts all of the registered users which there is a collection named registered-users in my MongoDB.
Here is how I accomplished that:
const User = require("../models/User")
const Topic = require("../models/Topic")
router.get('/', async (req, res) => {
await User.count((err, registeredUsers) => {
if (err){
console.log(err)
} else {
res.render("register", {registeredUsers})// using EJS for my template engine
}
})
})
so this let's me count the total users registered but I have another collection in the db named topics that I would like to get a total count of as well. how can I do that without having to res.render again (I'm not even sure if that works or not) and pass in another object? Is this possible to count the users and the topics (which is a different collection and model)?
The goal is that in the ejs it has something that says :
Total Users signed up: registeredUsers
Total Topics created: totalTopics

Model.count()
Counts number of documents that match filter in a database collection.
This method is deprecated. If you want to count the number of documents in a collection, e.g. count({}), use the estimatedDocumentCount() function instead. Otherwise, use the countDocuments() function instead.
source: https://mongoosejs.com/docs/api.html#model_Model-count
Also, since you are using async function, we can use Promise.all() to run queries in parallel.
const User = require("../models/User")
const Topic = require("../models/Topic")
router.get('/', async (req, res) => {
const [userCount, topicCount] = await Promise.all([
User.countDocuments({}),
Topic.countDocuments({})
])
// using EJS for my template engine
res.render("register", {
registeredUsers: userCount,
totalTopics: topicCount
})
})

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

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
}

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

Firestore Cloud Function empty collection

I have a problem that's bugging me for days. I am trying to create a Firebase Cloud function that reads from the Firestore database.
My Firestore DB looks like this:
Problem is that I cannot list users like this:
db.collection('users').get().then((snapshot) => snapshot.forEach(...));
If I try to do this I get empty response, like there are no users in my users collection.
But I try to access user directly it works:
await db.collection('users/5CZxgu8nmNXu2TgplwOUdOIt8e33/receipts').get()
My complete code:
import * as functions from 'firebase-functions';
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.cat = functions.https.onRequest(async (req, res) => {
const receiptList: any = [];
const db: Firestore = admin.firestore();
const usersRef = await db.collection('users').get();
console.log(usersRef.empty); // Returns true
const receiptsRef = await db
.collection('users/5CZxgu8nmNXu2TgplwOUdOIt8e33/receipts')
.get();
receiptsRef.forEach((receipt: any) => {
console.log(receipt);
receiptList.push(receipt);
// Here I can access data
});
res.send(receiptList);
return '';
});
Does anyone have any idea what I'm doing wrong? Thank you!
Your users collection is actually empty. See how the document IDs are shown in italics? That means there is not actually a document in its place, however, there are subcollections with documents organized underneath them.
When you query a collection, you only get the documents that are immediately within that collection. A query will not pick up documents organized in subcollections. In this respect, queries are said to be "shallow". As you've seen, you need to reach deeper into the subcollection to get its documents.
Bottom line is that the queries you're showing are doing exactly what they're supposed to do.
Thanks again Doug for your help.
I manage to solve my problem. Here is my complete solution.
import * as functions from 'firebase-functions';
import {
Firestore
} from '#google-cloud/firestore';
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.cat = functions.https.onRequest(async (req, res) => {
const receiptList: any = [];
const db: Firestore = admin.firestore();
const receipts = await db.collectionGroup('receipts').get();
receipts.forEach((doc: any) => {
console.log(doc.id, ' => ', doc.data());
receiptList.push(doc.data());
});
res.send(receiptList);
return '';
});
.get() gets all documents. In your case those documents are empty therefore .get() doesn't consider them.
The simplest solution that I found for this is to replace .get() with .listDocuments(). Now you could read each doc entry like you would a doc.

Multiple MongoDB queries in a Javascript function?

How can I execute the following queries together in a single javascript function for mongoDB?
//find the reviews from the reviews collection
var proRev = db.reviews.find({productID: "123"}).toArray();
//update the products collection
db.products.update({productID : "123"},{$push:{Reviews:proRev}},{multi:true});
//remove the reviews from the reviews collection
db.reviews.remove({productID: "123"});
The function would be based on finding the reviews for productID "123" from a reviews collection, and inserting them as an array, in a new field for productID "123" found in the products collection.
Rather than executing the queries seperate, I would like them to execute in a single function - I'm a javascript noob so sorry if this is a stupid question.
Thanks
Use promises.
Example:
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
const dbName = 'myproject';
(async function() {
let client;
try {
client = await MongoClient.connect(url);
console.log("Connected correctly to server");
const db = client.db(dbName);
const [res1, res2] = await Promise.all([
db.collection('inserts').findOne({
foo: "bar"
}),
db.collection('inserts').findOne({
bar: "foo"
})
]);
} catch (err) {
console.log(err.stack);
}
// Close connection
client.close();
})();
If you want to do it in one operation within MongoDB, try using findOneAndUpdate

Categories