Node.js, Apollo Server, GraphQL, Mongoose – Category Tree

Node.js, Apollo Server, GraphQL, Mongoose – Category Tree


0

I am trying to create Category Tree with Node.js, Apollo Server, GraphQL, Mongoose technologies.

But when I want to get the created Category or Subcategory data, the output is not what I want.

Output;

{
  "data": {
    "getCategories": {
      "success": true,
      "response_code": "categories-successfully-retrieved",
      "message": "Categories Successfully Retrieved!",
      "categories": [
        {
          "_id": "655a1b6018951b0985fd7635",
          "name": "K 1",
          "subCategories": [
            {
              "_id": "655a1b7018951b0985fd763e",
              "name": "A K 1"
            },
            {
              "_id": "655a1b8b18951b0985fd764e",
              "name": "A K 2"
            },
            {
              "_id": "655a1e9e774c59f9a383fcd9",
              "name": "A K 3"
            }
          ]
        },
        {
          "_id": "655a1b6218951b0985fd7638",
          "name": "K 2",
          "subCategories": []
        },
        {
          "_id": "655a1b6418951b0985fd763b",
          "name": "K 3",
          "subCategories": []
        },
        {
          "_id": "655a1b7018951b0985fd763e",
          "name": "A K 1",
          "subCategories": [
            {
              "_id": "655a1b7c18951b0985fd7643",
              "name": "A A K 1"
            }
          ]
        },
        {
          "_id": "655a1b7c18951b0985fd7643",
          "name": "A A K 1",
          "subCategories": [
            {
              "_id": "655a1b8318951b0985fd7648",
              "name": "A A A K 1"
            }
          ]
        },
        {
          "_id": "655a1b8318951b0985fd7648",
          "name": "A A A K 1",
          "subCategories": []
        },
        {
          "_id": "655a1b8b18951b0985fd764e",
          "name": "A K 2",
          "subCategories": []
        },
        {
          "_id": "655a1e9e774c59f9a383fcd9",
          "name": "A K 3",
          "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.

New contributor

Knâkles is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.


Load 5 more related questions


Show fewer related questions

0



Leave a Reply

Your email address will not be published. Required fields are marked *