Hi there,
I have the following schema:
Article
Category
Tag
Each Article belongs to a Category, and an Article can have many Tags. So something like this:
{
id: 1,
title: "My article",
category: {
id: 1,
name: "News"
},
tags: [
{
id: 3,
name: "Tag 3"
},
{
id: 4,
name: "Tag 4"
}
]
}
When viewing the ‘News’ category, I’d like to be able to display all the tags associated with articles that belong to that category. So I’m looking to get something like this:
{
id: 1,
name: "News",
articles: [
{
id: 1,
title: "My article",
tags: [...]
},
{
id: 2,
title: "Another article",
tags: [...]
}
},
tags: [ // Tags associated with all articles that belong to this category.
{
id: 3,
name: "Tag 3"
},
{
id: 4,
name: "Tag 4"
}
]
}
One way would be to fetch all articles, and extract the tags that way (but that seems somewhat inefficient).
Instead, I’ve written the following query that gets all the article Ids associated with the given category, and then uses that to find all the tags Ids in the join table:
// api/category/controllers/category.js
const getCategoryTags = async (category) => {
let tagIds = await strapi.connections.default.raw(
`SELECT * FROM articles_tags__tags_articles WHERE article_id in (${articleIds.join()})`
);
tagIds = JSON.stringify(tagIds.rows);
tagIds = JSON.parse(tagIds).map((a) => a.tag_id);
const tags = await strapi
.query("tag")
.model.query((qb) => {
qb.where("id", "in", tagIds);
})
.fetchAll({
withRelated: [
{
articles: (qb) => {
qb.where("category_id", "=", category.id);
},
},
],
});
return tags.toJSON();
}
module.exports = {
find: async (ctx) => {
const { slug } = ctx.query;
const categories = await strapi
.query("category")
.find(ctx.query, ["articles.tags", "quote.person"]);
if (slug && categories[0]) {
categories[0].tags = await getCategoryTags(categories[0]);
}
return categories;
},
findOne: async (ctx) => {
const category = await strapi
.query("category")
.findOne({ id: ctx.params.id }, ["articles.tags"]);
category.tags = await getCategoryTags(category);
return category;
},
};
The above works perfectly, but I’d like to find a way to translate this over to Graph QL. I’m unsure whether:
a.) GraphQL already has a built in way of doing the above (which would make the above code redundant)
b.) If not, what is the best way to implement this? Do I need to write a custom resolver?
Any help greatly appreciated!