How to ignore a query field in MongoDB - node.js

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.

Related

How to make mongodb and nodejs response fast?

I have a blog schema(title, topic, body, author, etc) and a function to return all the blogs in that document.
Right now I am just doing Blog.find() to pull all the data at once and sending the responses using res.send(). The problem is the body property of the blog is very large and it takes a lot of time to return the results.
Is there any way to make it fast.
You can get faster results if you add the fields you use the most in searches to the collection as an index.
Usage example:
//The following example creates a single key descending index on the name field:
db.collection.createIndex( { name: -1 } )

Dynamically accessing Mongodb database collection based in URL parameters

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

How to expose MongoDB documents primary keys in a REST API?

I am building a REST API with MongoDB + nodeJS. All the documents are stored and are using _id as the primary key. I've read here that we should not expose the _id and we should use another ID which is not incremental.
In the DB, a document is represented as:
{
_id: ObjectId("5d2399b83e9148db977859ea")
bookName: "My book"
}
For the following the endpoints, how should the documents be exposed?
GET /books
GET /books/{bookId}
Currently my API returns:
{
_id: "5d2399b83e9148db977859ea"
bookName: "My book"
}
but should it instead return something like:
{
id: "some-unique-id-generated-on-creation"
bookName: "My book"
}
Questions
Should I expose the _id so that one can make queries such as:
GET /books/5d2399b83e9148db977859ea
Should I use a UUID for my ID instead of ObjectId?
Should I keep the internal _id (but never expose it) and create another attribute id which would use UUID or another custom generated ID ?
Is it a good practice to work with _id in my backend or should I only make queries using my own custom ID? Example: find({ id: }) instead of find({ _id: })
To answer your questions.
You can expose _id so that authenticated users can make queries like GET, PUT and PATCH on that _id.
MongoDB has support that allows you to generate your own BSON ID and use it, instead of mongodb created it's own _id during the insert.
There is no need of duplicating logic, the main purpose of _id is to identify each document separately and having two id columns means you are storing redundant data, follow DRY (DO NOT REPEAT YOURSELF) principle wherever possible.
It's not a bad practice to work with _id in your backend.
Hope this helps!
Given you're using Mongoose, you can use 'virtuals', which are essentially fake fields that Mongoose creates. They're not stored in the DB, they just get populated at run time:
// Duplicate the ID field.
Schema.virtual('id').get(function(){
return this._id.toHexString();
});
// Ensure virtual fields are serialised.
Schema.set('toJSON', {
virtuals: true
});
Any time toJSON is called on the Model you create from this Schema, it will include an 'id' field that matches the _id field Mongo generates. Likewise you can set the behaviour for toObject in the same way.
You can refer the following docs:
1) https://mongoosejs.com/docs/api.html
2) toObject method
In my case, whether it's a security risk or not, but my _id is a concatenation of any of the fields in my Document that are semantically considered as keys, i.e. if i have First Name, Last Name, and Email as my identifier, and a fourth field such as Age as attribute, then _id would be concatenation of all these 3 fields. It would not be difficult to get and update such record as long as I have First Name, Last Name and email information available

Algolia Key Value Search

I am currently working with the Algolia search API and I am unable to figure out how I would limit the results by key value searching + query string. By this i mean this.
I have a list of properties.
Each property belongs to a client.
Within the application If i am looking at a client information card and I want to search for a property that client owns It would make more sense to limit the results to the client and then look for the query string.
I am using MongoDB as my DB and storing the client id as a sub document like so
//Property Document
{
_id : "randomID"
client : {
_id : "randomID",
name : "ClientName"
}
}
If you want to restrict the search to a specific client, I would go for facet filtering to restrict the search to that client only.
Add client._id in the attributesForFaceting in your index settings
Filter your searches with the facetFilters=client._id:MYCLIENTID query parameter
Then, you should also take a look at the Secured API keys which are able to encode such restriction in a secure way (so the end-user cannot patch the JS code and work-around the filtering).
There is parameter called restrictSearchableAttributes[link] to restrict, at query time, search to some attributes only. Nevertheless, in your case I think you'd get more accurate results by putting each client info into a different record (+ the info of the related document).

Basic CouchDB Queries

I've never worked with a database before, but I chose Couch DB because I needed a Json database, and HTTP queries seemed kinda simple. However the documentation assumes a level of knowledge I just don't have.
Assuming I have a database called 'subjects', it seems I can access the json by using GET on
http://localhost:5984/subjects/c6604f65029f1a6a5d565da029001f4c
However beyond that I'm stuck. Ideally I want to be able to:
Access a list of all the keys in the database (not their values)
Access an individual element by its key
Do I need to use views for this? Or can I just set fields in my GET request? Can someone give me a complete example of the request they'd use? Please don't link to the CouchDB documentation, it really hasn't helped me so far.
Views can be used to fetch the data
1) In order to get all keys from the database you can use below view
function(doc) {
if (doc.type=="article")
emit(doc._id,null); //emit(key,value), if you have any other field as key then specify as doc.key e.g doc.
}
You can access this view from browser using below URL
http://<ipaddress>:<port>/databasename/_design/designdocumentname/_view/viewname
e.g :
http://<ipaddress>:<port>/article/_design/articlelist/_view/articlelist
article is the database name,articlelist is name of the design document as well as view.
2) In order to access individual document by key
Below view will return all the articles belonging to a particular department
function(doc) {
if(doc.type == 'article' ) {
emit([doc.departmentname], doc);
}
}
Query this view based on the "department name"
e.g: Get all the articles belonging to "IBU3" department
http://<ipaddress>:<port>/department/_design/categoryname/_view/categoryname?key=[%22IBU3%22]

Resources