0

I am new to MongoDB and CRUD APIs. I have created my first database and inserted some data. I can do get, post and delete requests.

Now I want to request a 'get' by adding a parameter, so I do the following:

router.get('/:story_name', async function (req, res, next) {
  const selectedStory = await loadStoryToRead()
  res.send(await selectedStory.find({}).toArray())
})

say that story_name is S1C1,

I can do http://localhost:3000/api/whatever/s1c1 to get the data.

I would have expected to retrieve the data ONLY by using the specified parameter, however I can use the ID or the date or any other parameter found in the json file to get the data.

for example I can do

http://localhost:3000/api/whatever/5d692b6b21d5fdac2... // the ID

or

http://localhost:3000/api/whatever/2019-08-30T13:58:03.035Z ... // the created_at date

and obtain the same result.

Why is that? How can I make sure that if I use router.get('/:story_name' ... I can retrieve the data only if I use the 'story_name' parameter?

Thanks!

* UPDATE *

my loadStoryToRead() looks like this:

async function loadStoryToRead () {
  const client = await mongodb.MongoClient.connect(
    'mongodb+srv://...', {
      useNewUrlParser: true
    })
  return client.db('read').collection('selectedStory')
}

I will try to reformulate my question.

I want to ensure that the data is retrieved only by adding the 'story_name' parameter in the URL and not by adding any other parameter within the file.

The reading that I have done suggested to add the parameter to the get request, but when I do it, it doesn't matter what parameter I enter, I can still retrieve the data.

The delete request, however, is very specific. If I use router.delete('/:id'... the only way to delete the file is by using the ID parameter.

I would like to obtain the same with a get request and not using the 'id' but by using 'story_name'.

Marcello
  • 173
  • 1
  • 15
  • 1
    *"I would have expected..."* - When you say you **expect** then perhaps there is some functionality in your `loadStoryToRead()` function which you *think* is doing something but is not. Notably you are not passing in ( or utilizing ) `story_name` anywhere, so that's a main consideration. Also that function likely is not ( and should not be ) `async`, unless there is a general attempt in the function to get ( or reuse ) a connection to the database, which is the only *async* action which *should* exist up to that point. i.e `db.collection()` is NOT an *async* operation. – Neil Lunn Aug 30 '19 at 23:51
  • 1
    In general though, personally I would separate the *"set the query parameters"* functionality into different routes i.e "by_name" and "by_id". Then pass the actual "get the data" functionality to a common function with the set query parameters. But your question here generally seems to be lacking the code to the `loadStoryToRead()` function in order to correctly assess exactly what has been done incorrectly and how to correct it to *your expectations*. Better to revise the question with the new information or just generally consider *separate routes* as an advised *"better practice"*. – Neil Lunn Aug 30 '19 at 23:55
  • I am sorry, but I do not understand the answer. leaving aside the "async" issue (which I will do a bit more reading, thanks for the heads up), are you suggesting to work on the loadStoryToRead() function and not on the 'get' to ensure the data is retrieved only if using that parameter? – Marcello Aug 31 '19 at 08:35
  • 1
    You have a bit more reading to do. As suspected the function connects to MongoDB in **every** invocation, and this is **very bad**. Please see [How to properly reuse connection to Mongodb across NodeJs application and modules](https://stackoverflow.com/q/24621940/2313887) for information on how to do that properly. As for the rest of your question, right now all your code does is `find({})` which has no constraints at all and returns **everything** in the collection. In order to return **one thing** you need to give it parameters like `find({ _id: ObjectId(story_name) })` in the case of an id. – Neil Lunn Aug 31 '19 at 08:38
  • 1
    Basically what I otherwise said was have a route `/api/whatever/by_id/:id` for retrieval by `_id` and `/api/whatever/by_date/:date` for date. You can then just do something like `let query = { _id: id }` in the `by_id` route ( for example, and similar in the other )` and have both call a `getData(query)` function which actually uses the `query` on the collection. That's if simply `db.collection('selectedStory').findOne({ _id: id })` seems like it really needs reuse to you. Personally I'd use the methods directly in each route without a common function. – Neil Lunn Aug 31 '19 at 08:43

1 Answers1

0

you can use regular expression capabilities for pattern matching strings in queries.

Syntax is:

db.<collection>.find({<fieldName>: /<string>/})

for example, you can use

var re = new RegExp(req.params.story_name,"g");
db.users.find({$or:[{"name": re}, {"_id": re}, {..other fields}]});

You can use $and and $or according to your requirement.

To read more follow the link https://docs.mongodb.com/manual/reference/operator/query/regex/

Vinesh Goyal
  • 607
  • 5
  • 8
  • 1
    Whilst it's *possible* in *"some cases"* to use an open regular expression with `$or`, it's just not going to work here. The `_id` is *most likely* actually an `ObjectId` and **NOT** a "string", so an Re just does not work. Also ANY open ended Re ( i.e no caret `^` ) is **really bad for performance**. See also the very same manual page you reference for that exact advise. It's all stated in that page. – Neil Lunn Aug 30 '19 at 23:59
  • 1
    Also FYI. From MongoDB 4.2 onwards it is again *"possible"* to *coerce* an `ObjectId` value into a "string" and use a Regex comparison function ( introduced as aggregation operators `$regexFind` etc ) with a *brute force* operation on the whole collection. However this is **really bad** for performance, and possibly even worse so than just an open ended Regex itself. So basically, *do not do this* and instead separate the query generation by parameters instead. – Neil Lunn Aug 31 '19 at 00:07
  • @NeilLunn: Thanks for your advice and its appreciatable. The poster didn't specify the mongo version so we have to suggest generic solutions. Use of caret "^" is a good suggestion but it depends on user requirement. – Vinesh Goyal Sep 03 '19 at 21:24