I have noticed in Geddy that when I create a model and a subsequent record for that model, I get a very ugly model ID associated with the record. Something like:
http://localhost:4000/posts/3FEEDE8D-2669-445B-AEA1-A31092A7FEDA
Is there a way to change this?
Ideally, I would always want this to be some sort of string. Where it be for a post or user:
http://localhost:4000/posts/this-is-a-post-title
http://localhost:4000/profile/meebix
If this is possible, how should I:
Configure routes
Change primary key for model
Other implementation steps I may need
Thanks!
Yes, you can change the id if you really want to, but you'll be going off the beaten path there, so it's quite a bad idea. Let Geddy handle IDs for you.
The way I would do this (and certainly how many others have too) is to have a "slugging" function create a slug from the post title, and save that in your database. Then, query on that instead in your show action. You won't have to change your routes.
This is what your query will look like in the show action:
Post.first({slug: params.id}, function (err, post) {
params.id is whatever string you use in the route /posts/<this string>
So once you change your show links to use the slug instead of the ID you will be all set!
Related
I am needing to make some sharable blog post URLs. To do that, the URL must be something like webpage.com/blog-post-title. It cannot be webpage.com/5GFd5GDSg2345WD.
Since I am using dynamic routing, I need to get a Contentful entry using nothing but what is on the URL. There should not be any queries because queries are ugly and reduce shareability, like webpage.com/blog-post-title?query=queriesAreUgly.
Unfortunately, I need the entryId to get the entry. Also unfortunately, the entryIds are all very ugly and therefore completely useless/unusable. I wish I could set my own entryId, but this does not appear to be possible for mysterious reasons.
I could make a lookup table that pairs URLs with entryIds, but I'm going to be handing this contentful project to someone who is not tech savy, and they should not have to manage a lookup table.
I could get all blog entries then filter by blog title, but, very obviously, this is inefficient, as I would be loading thousands of lines of text for no reason at all.
I could create my own backend API and doing all this myself, but this is also a bad solution because it would take too much time and I could not give it to my non-tech-savvy client.
There are seemingly no solutions to this problem which created by Contentful's inherent needless inflexibility.
The only efficient way to get this to work is to find the entry not by its ID but by one of its fields. Is there a performant/efficient way to do this, or am I just going to have to filter through every single blog post until I find the one with the correct title?
How about adding a 'slug' field to the blog post content type, which you can auto-generate from the title using the field settings (so you don't have to type it out manually?)
You can then filter on the slug field in the query.
If you're using the JavaScript SDK (which it sounds like you are), you can use getEntries() and filter by the slug field to get a single blog post. Like so:
import { createClient } from "contentful";
const client = createClient({
space: {SPACE_ID},
accessToken: {ACCESS_TOKEN},
});
const response = await client
.getEntries({
content_type: "blogPost",
limit: 1,
"fields.slug": "blog-post-title",
})
.then((entry) => entry)
.catch(console.error);
I have my data model already defined and implemented. I can very easily write manually the filter to filter out non-authorized results for the user who sent the query (which would be in the style of: "collection.acl.personId": queryPersonId )
My problem is, where and how should I write this "thing" to be as automatic as possible?
I tried to do it with a custom query and a static method, but did not had any luck on both.
Static method con: I don't want to rewrite all my code to use .then(). I want to keep the current chaining.
Custom query: it simply did not worked, even by following the doc.
Ideal the result would be something like
Model.findWithAcl(filters).lean()
Model.findOneWithAcl(filters).lean()
Note that we are using Typescript. The priority would be to have something working, but having the ability to have a working type would be the second priority right after.
Thanks for any help
Casl mongoose gives a very good way of filtering both results (row level) and fields from collections. Note that it also can be used in the front end.
Great package that works very well with auth0 rights.
https://casl.js.org/v5/en/guide/intro
https://casl.js.org/v5/en/package/casl-mongoose
In my app i have stores and products, in my store side i have a reference to products, my daubt now is how i set the route to delete a product for a store
should i do something like this router.delete('products/:id') this deletes a product since the store has a reference i just need to delete the reference, but my store has a id actually my store is my user, so i want to be sure that there is a user to be able to delete something i was imaginating something like this:
router.delete('stores/:id/products/:id'), but that feels kinda strange, what you guys think about this?
I believe your concern is that you have two parameters id in request string. Express supports specifying many parameters and you can name them whatever you like, they should be parsed and available to you as variables later (req.params.productId).
So you can do
router.delete('stores/:storeId/products/:productId')
Additional information you can find in express routing documentation.
How, by using the 'findOne'/'find' functions of mongoose, can I find a specific document, where the results are filtered by a virtual field which does not appear physically in the db?
I'll try to further explain:
In my 'User' model, I have a field called 'email'. I want to create an alias for 'email' as 'userkey' for other functions in my nodejs app (mostly login validations and stuff).
To create the alias, I did this:
userSchema.virtual('userkey').get(function()
{
return this.email;
});
Now, after I created the alias, I want to filter my search result the following way:
restApi.post('/login', function (req, res) // (using expressjs)
{
User.findOne({'userkey': req.body.userkey}).exec(..);
}
How can I do this efficiently and without creating any more methods\field etc to save up time and memory?
The alias is very important, because in the future of the app I'll add more ways to login, and I want to be able to quickly switch between fields to be associated with 'userkey'. This alias saves the trouble of changing the entire app (which is a huge programming principle), and can help me to add more logic which is going to be necessary in the future.
You can't.
Virtuals do not exist on the document stored in mongodb, so there's nothing to query on.
I have a problem that I can't seem to find a proper solution for.
First of all, I'm using the meanjs framework, which mean I use express, nodejs, mongoose and mongodb in the backend!
The problem goes like this: Every time I want create a post, I attach a user to the post as it's creator, this is done by using the Schema.ObjectId type in mongoose.
When I create a post I want to give the user a point. So the flow would be something like this:
Create post-> post.created-> post.postCreator.points+=1
I wanna implement this logic for more things, such as, if others liked your post, you would also recieve a point. The flow would be something like this for that:
Like post->post.likes+=1->post.postCreator.points+=1
I want this to be done completely in backend but I'am not sure how I would implement this sort of functionality correctly..
In both the examples the post.postCreator is a Schema.ObjectId type, where it references the correct User document.
If someone could point me in the right direction how this should be implemented I would really appreciate it.
Thanks in advance!
If you have the user id from your Post instance, you would then need to query and update the User. Example:
schema.post('save', function(p) {
UserSchema.findByIdAndUpdate({'_id': p.userId}, {$inc: {points: 1}},
function(error, user) {
// do something else with the user if necessary
}
);
});