There are a lot of ways to do this, and you haven't described your DB or ORM or the like, but implied that you have something along those lines with your terminology.

The simplest thing to do would be to just assume that this is not a concern of the storage, but instead it's something that you'd apply globally to the api, so that all routes have it applied. This could be in the form of middleware:

router.use((req, res, next) => {
if (res.data) { // if you do it this way, none of your routes will actually do a res.send, but instead will put their data into res.data and rely on another middleware to render or send it
res.data._links = {
self: calculateSelf(req, res.data),
collection: calculateCollection(req, res.data)
};
}
});

Given that, those two link calculators could use some standard patterns or regex to figure out what the link should look like generically.

Alternatively, if you're using Mongoose, you could override toJSON to populate those links in any models you expect to send down the wire, but that implies that your models should be aware of what the root application URL is, which I don't recommend.

For that to work, you have to pass { virtuals: true } to toObject() or toJSON() or set it as a global mongoose configuration to always show virtuals. As I said before, though, I really wouldn't recommend that as it requires the schemas to have access to and knowledge of the base URL, which can change between environments. If (as your schema implies) the model is representing a web page, then the URL template could be something that is actually relevant to the model, but in most domains that wouldn't be the case and so I'd recommend the middleware approach.