DEV Community

loading...

Discussion on: How to build dynamic mongoose queries

Collapse
evanjameson profile image
Evan Jameson • Edited

I can’t even begin to tell you how timely this post is.

I was curious, when it comes to defining the schema for your model do you need to be completely explicit?

I have a large dataset where some of my keys can be different values and some key:value pairs vary in size. (I’m scraping a website for my data that varies heavily between pages) I'm using "Schema.Types.Mixed" to account for this:

gist.github.com/EvanJameson/b44815...

Could this lead to major issues down the road? Do you think I need to restructure how I structure the data I scrape?

Collapse
itz_giddy profile image
Audiophile Author

Hi Evan thanks for reaching out. Now I've personally never had to use Mixed schema types in my work, but reading the mongoose docs on Schema.Types.Mixed explicitly states that while you may be able change the value of the field to whatever you like, Mongoose will lose the ability to auto detect and save those changes, meaning you can't just do a 'model.save()' after making changes to the mixed field on your schema, you need to call model.markModified('field_path'); before your model.save(). Depending on the number of controller functions you have or may need in future, the possibility of forgetting to add that line for every modification to your mixed field type is pretty high. I would suggest that you make the schema for your model as explicit as possible. It'll save you alot of headache down the line when you need to perform complex queries, because you wouldn't need to keep checking your model for changes in its value type. I hope this helps.

Collapse
evanjameson profile image
Evan Jameson • Edited

Hi again! I followed your guide here and had a question:

When it comes to "${API}/search" where is API defined? Is the specified API path based on the request? Learning a lot from scratch here so this may be a rather rudimentary question.

Prior to following your guide I was getting the user specified value via req.query.params and using the path format "/:athleteName" where the request path would look like

-url here-/athletes/-name here-

What should the request look like when following your guide?

You can see my route here:

gist.github.com/EvanJameson/aebe11...

You can see my controller here:

gist.github.com/EvanJameson/2592d1...

Thread Thread
itz_giddy profile image
Audiophile Author

Hi Evan! I apologize for not being clear on the API path. In JavaScript it is advisable to always store values that are least likely to change in variables for two reasons: 1.) ease of use in multiple places 2.) It reduces typos. So usually if I have an endpoint like:

 'http://localhost:5000/api/students/search'
Enter fullscreen mode Exit fullscreen mode

My base url will be: localhost:5000/api/students while my search endpoint would be: /search. Now if I have 10 different endpoints doing different things, having to type my base url multiple times would slow me down. So instead I do something like:

 const API = 'http://localhost:5000/api/students'
Enter fullscreen mode Exit fullscreen mode

And then for each route path, I use es6 string literals to concatenate the base url and the search endpoint like so:

 router.get(`${API}/search`)
Enter fullscreen mode Exit fullscreen mode

So even if I have 20 routes to build, all I have to do is use string literals to concatenate the base url and route path:

 router.get(`${API}/route1`)

 router.get(`${API}/route2`)
 .
 .
 .
router.get(`${API}/route20`
Enter fullscreen mode Exit fullscreen mode

Now for the '/:athleteName' convention, there's nothing wrong in doing it that way, it's part of RESTful convention to show other developers that it is a query parameter. Although when testing the endpoint with Postman there is a slight difference in the way you would do it.

You see adding '/:athleteName' means that when sending your request(in Postman) you would have to type something like:

 'http://localhost:5000/api/athletes/Evan'
Enter fullscreen mode Exit fullscreen mode

in your get request. You may not be able to add it to the query params field in Postman to get something that looks more like:

 'http://localhost:5000/api/athletes?athleteName=Evan'
Enter fullscreen mode Exit fullscreen mode

You can see that the two requests are different even though you would eventually get the same result either way.

Here's the thing, your 'req' and 'res' are objects that have properties attached to each of them. The request object(req) has a 'query' property that is also an object. For example:

 const req = {
            query:{ athleteName }
             }
Enter fullscreen mode Exit fullscreen mode

So if I wanted to get the athleteName(in my controller function) from a get request without having to use the '/:athleteName' convention, I would just get it this way:

  const athleteName = req.query.athleteName;

   or with destructuring

const { athleteName } = req.query;
Enter fullscreen mode Exit fullscreen mode

Doing it this way means I can write routes like 'localhost:5000/api/athlete/athlete...' without having to use the colons. Subtle difference but doesn't stop your code from working, only changes how you would test with Postman(at least in my case it did). I hope this helps.

Thread Thread
awkwardblkcoder profile image
Phoebe M

I love how this reply was its own mini tutorial! lol so thorough

Thread Thread
itz_giddy profile image
Audiophile Author

Thanks Phoebe!