I am trying to create Category Tree with Node.js, Apollo Server v4, GraphQL, Mongoose technologies.
But when I want to get the created Category or Subcategory data, the output is not what I want. Categories appear both in subCategories as a reference and as a normal category. I also added category data with this id 655b105543598f2ef0ba0f69 as the 2nd subCategory in the subCategories array of the category with this id 655b104a43598f2ef0ba0f64 value in a way I don’t understand. But although the name does not appear null.
GraphQL Query Request;
query Query {
getCategories {
success
response_code
message
categories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
}
}
}
}
}
}
}
Output;
{
"data": {
"getCategories": {
"success": true,
"response_code": "categories-successfully-retrieved",
"message": "Categories Successfully Retrieved!",
"categories": [
{
"_id": "655b103b43598f2ef0ba0f5e",
"name": "K 2",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
},
{
"_id": "655b103e43598f2ef0ba0f61",
"name": "K 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": [
{
"_id": "655b104a43598f2ef0ba0f64",
"name": "AK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": [
{
"_id": "655b105543598f2ef0ba0f69",
"name": null,
"attributes": null,
"products": null,
"subCategories": null
}
]
},
{
"_id": "655b106643598f2ef0ba0f6f",
"name": "AK 2",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
}
]
},
{
"_id": "655b104a43598f2ef0ba0f64",
"name": "AK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": [
{
"_id": "655b105543598f2ef0ba0f69",
"name": "AAK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
}
]
},
{
"_id": "655b105543598f2ef0ba0f69",
"name": "AAK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
},
{
"_id": "655b106643598f2ef0ba0f6f",
"name": "AK 2",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
}
]
}
}
}
Expected Output;
[
{
"name": "Category 1",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 1",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 2",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": []
}
]
}
]
},
{
"name": "Category 2",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 1",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 2",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": []
}
]
}
]
}
]
Category Mongoose Schema;
import mongoose from "mongoose";
const attributeSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true, unique: true, default: "Default Name" },
values: [
{
value: { type: String, required: true, trim: true, unique: true },
products: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
},
],
});
const categorySchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
subCategories: [{ type: mongoose.Schema.Types.ObjectId, ref: "Category" }],
attributes: [attributeSchema],
products: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
});
export const Category = mongoose.model("Category", categorySchema);
Category GraphQL Schema;
export const categorySchema = `#graphql
type Category {
_id: ID
name: String
subCategories: [Category]
attributes: Attributes
products: [Product]
}
input CategoryInput {
name: String!
isMainCategory: Boolean!
parentCategoryID: ID
}
type Attributes {
name: String
values: AttributesValue
}
type AttributesValue {
value: String
products: [Product]
}
input AttributesInput {
name: String!
categoryID: ID!
}
input AttributesValueInput {
value: String!
attributesID: ID!
}
type QueryCategoryResponse {
success: Boolean!
response_code: String!
message: String!
category: Category
categories: [Category]
}
type Query {
getCategories: QueryCategoryResponse
getCategoryByID(id: ID!): QueryCategoryResponse
getCategoriesByID(ids: [ID]!): QueryCategoryResponse
}
type Mutation {
createCategory(input: CategoryInput!): Response
}
`;
Category Resolver;
import { Category } from "./model.js";
export const categoryResolver = {
Query: {
getCategories: async () => {
try {
const categories = await Category.find().populate("subCategories attributes products");
if (categories) {
return {
success: true,
response_code: "categories-successfully-retrieved",
message: "Categories Successfully Retrieved!",
categories: categories,
};
} else {
return { success: false, response_code: "categories-not-found", message: "Categories Not Found!" };
}
} catch (error) {
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
getCategoryByID: async (_, { id }) => {
try {
const category = await Category.findById({ _id: id }).populate("subCategories attributes products");
if (category) {
return {
success: true,
response_code: "category-successfully-retrieved",
message: "Category Successfully Retrieved!",
category: category,
};
} else {
return { success: false, response_code: "category-not-found", message: "Category Not Found!" };
}
} catch (error) {
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
getCategoriesByID: async (_, { ids }) => {
try {
const categories = await Category.find({ _id: { $in: ids } }).populate("subCategories attributes products");
if (categories.length !== 0) {
return {
success: true,
response_code: "categories-successfully-retrieved",
message: "Categories Successfully Retrieved!",
categories: categories,
};
} else {
return { success: false, response_code: "categories-not-found", message: "Categories Not Found!" };
}
} catch (error) {
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
},
Mutation: {
createCategory: async (_, { input }) => {
try {
if (input.isMainCategory) {
const category = await Category.findOne({ name: input.name }).collation({ locale: "en", strength: 2 });
if (category) {
return { success: false, response_code: "category-name-exist", message: "Category Name Exist!" };
} else {
const newCategory = new Category({
name: input.name,
});
await newCategory.save();
return {
success: true,
response_code: "category-created-successfully",
message: "Category Created Successfully!",
};
}
} else {
const category = await Category.findById(input.parentCategoryID).populate("subCategories");
if (!category) {
return { success: false, response_code: "sub-category-not-found", message: "Sub Category Not Found!" };
}
const categoryNames = category.subCategories.map((category) => category.name.toLowerCase());
if (categoryNames.includes(input.name.toLowerCase())) {
return { success: false, response_code: "category-name-exist", message: "Category Name Exists!" };
}
const newCategory = new Category({
name: input.name,
});
await newCategory.save();
category.subCategories.push(newCategory);
await category.save();
return {
success: true,
response_code: "sub-category-created-successfully",
message: "Sub Category Created Successfully!",
};
}
} catch (error) {
console.log(error);
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
},
};
How can i improve this code and solve my getCategories output problem?
Obviously, I also tried with the mongoose ref, I also tried to do it by sending data directly into subCategories in accordance with the categorySchema. The method I mentioned in the 2nd method on adding subcategories etc. was a headache for me.
2
Can you tell us what output you are looking for?
12 hours ago
Something like this hastebin.com/share/ipexinaruj.json @MichelFloyd
2 hours ago