Dynamically accessing Mongodb database collection based in URL parameters - node.js

I have an API endpoint as api/get?subject=economics, and based on this subject parameter I access various database collections in mongodb. Right now I am using switch case statements to access the required database based on subject parameters. This is making my code very lengthy. Is there a way to access the database just by the subject parameter value? for example, instead of using this
const {subject}=req.query
switch (subject)
case "economics"
const data= await economics.find()
break;
I want to be able to use this
const {subject}=req.query
const data=await subject.find() // here subject will refrence its value like economics or stats

I think better way to pass modal as an argument. Here I is the code, How I have created common controller
https://gist.github.com/RMUSMAN/b7132fda6e945393882586c26b132e24
https://gist.github.com/RMUSMAN/c419d8149effb8514845946ad5b652f1
https://gist.github.com/RMUSMAN/f44ba2a20da35a2ce5ffd7517ea8fca8

Related

How can I select specific fields using the firestore modular api

In the <= V8 Firestore API I could query a set of documents and extract a subset of fields with code like the following:
const membersRef = db.collection('members');
const snapshot = await membersRef.select('First', 'Last').get();
With the new modular api I can do the following:
import { collection } from 'firebase/firestore';
const membersRef = collection(db,'members');
// how to select only First and Last from members ?
I can't find a select() function to specify fields in the new api. How can this be done using the V9 modular api?
I know I can read the entire collection and use .map()/.forEach to reduce the fields but I have some large fields I would rather not query unless I need them for a specific document. The use of select to have the server pull out only the fields needed is useful.
The client-side SDKs for Firebase don't have a select method/function, but always retrieve full documents. So the select method didn't exist in the v8 CollectionReference or Query classes, nor does it exist as a top-level function in the v9 modular SDK.
There is a select() method in the Admin SDK for Node.js, but that one still works as a method on CollectionRefence as far as I can tell.

Most effecient way to retrive and save data to mongodb via mongoose

Lets say we have a collection of user documnets in the mongodb database and each document contains huge amount of fields and data.
We may want to save the email of the user to its document right? So first we need to return the documnet of the user and then save the email :
const account = db.Account.findOne({email}); account.email = value; account.save;
As I said the document has a lot of extra fields we don't want to modify we only want to select and modify the email feild, Now I wonder :
if this has any impact on performance and the duration of the request?
2)Do I need to only select the email field for purpose of enhancing the performance?
What is the best practice to do this?

Why is data retrieved from Firestore returning empty array when there are subcollections present?

I am trying to retrieve data from my the my firestore database using angularfire2.
This is what my current database looks like. I have a users collection that contains the userId doc which binds the userDetails and userPosts together.
However when I query this collection, it returns an empty array in the console.
I am using a firebase function to retrieve the data.
Firebase Function Index.ts
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await admin.firestore().collection('users').get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
TS File
tabTwoFeedInit (){
const getFeed = this.aff.httpsCallable('getFeed')
this.ajax = getFeed({}).subscribe(data=> {
console.log(data)
this.posts = data
})
}
How can I retrieve data from this firebase database successfully?
Firestore reads are shallow, and so they won't return subcollections automatically. Thus, your get() will only return the document ID, since the document has no fields.
To return the subcollections of a document, you need to call the getCollections method on that document. This can only by done by the admin API, but that should be fine for you since you are running inside a cloud function. As the documentation notes, it is generally expected that collection names are predictable (as they appear to be in your case), but if they aren't, you might consider restructuring your data.
Why are shallow reads desirable? It makes it possible to avoid retrieving potentially large collections of information that might be associated with, say, a user, so you can structure data more naturally. Depending on the size of the data, its possible that a field that is a map might make more sense for userDetails (but a collection is probably the right thing for userPosts).
If you are just creating the cloud function to retrieve the posts from this structure. I would prefer to restructure the database a bit and just use Collection Group Query on client side (with no requirement of cloud functions) to pull the posts.
By restructuring I mean, you should store userID inside the documents of userPosts sub collection.
Then simply user Collection Group Query to retrieve post of specific users.
The syntax is of firebase javascript library. You can find it's equivalent of angularfire
let posts= db.collectionGroup('userPosts').where('userId', '==', 'some-user-id');
I also ran into the same problem but I solved it by adding a field to the particular document i am trying to retrieve.Sometimes the cause is because the documents you are trying to get has no field in it. What I mean is that a document must have a field before the server can recognize it as an existing document.
Possibly there may be no field in the document you are trying to retrieve which makes tye server say it is not existing and so will not be retrieved.
So if you run into this problem, then consider adding a field to that document before you can successfully retrieve it.

How to ignore a query field in MongoDB

Is there a way to ignore a field passed in a query? This issue is being caused by a query that is coming from an HTTP request.
For example this query would get all documents with title of some title and user's email of user#example.com
//From HTTP request
var query = {
title: 'some title',
'user.email': 'user#example.com'
};
somecollection.find(query, function(err, documents) {
//Not good because we know who posted these documents
});
The difficulty I'm having is that I'm working on an API that basically lets you pass a query to MongoDB and it returns the response. However, the part that is sensitive is that I don't want you to query by the user's email (because the document is supposed to be anonymous). I know you can limit the fields that are returned, but if you can query for all documents by user#example.com then those posts are no longer anonymous.
I guess I could try and delete that part of the query that is passed in from the HTTP request, but then I get into issues with someone using $or or any other operator that I don't know about or forget. Or if they use a string to access deeper parts of the user object.
Is there a way to limit what fields the query can query against?
If you don't want to expose all of the query logic, then don't allow the client to pass in a query. Create a separate endpoint that only accepts the the title as search parameter.
That being said, you could easily retrofit this by doing something like.
var title_only_query = {
'title': user_query.title
}
This way only the title property will be queried for.

Does mongoose support a declarative way to do sanitization (like lowercasing) when doing sets/finds?

Consider a field email which I'd like to set and query (findOne) over. I've created an unique index. Moreover, I'd like to enforce all email-addresses are lowercase according to best practice.
Of course I can make sure all my controllers that set and/or query by email will property lowercase first, but this is error-prone. Is there a way to offload this declaratively to mongoose/mongo instead? I.e.: passing Some#Example.com to Mongoose will properly by sanitized to some#example.com before setting the value or querying the collection.
You could use pre save middleware. This is coding but it would ensure that any call to save your document would lower case the email, no matter where it was saved from
userSchema.pre('save', function(next) {
var user = this;
user.email = user.email.toLowerCase();
next();
});

Resources