ChatGPT to the Rescue: Tackling a Coding Challenge Together!

ChatGPT to the Rescue: Tackling a Coding Challenge Together!

Created by eneaslari 10/9/2023

AI

Today, I encountered challenges with Mongoose, particularly regarding adding filters to queries that involve foreign keys. So, I sought assistance from ChatGPT-4. Here's a recap of our conversation:

💬 ME: I will provide you with three models, and I'd like your assistance in formulating some queries

💬 GPT-4: Of course! Please provide the three models, and let me know what specific queries or operations you'd like to perform on them. I'll do my best to help you out.

💬 ME:

const ArticleSchema = new mongoose.Schema(
    {
        title: {
            type: String,
            trim: true,
            required: 'Title is required'
        },
        description: {
            type: String,
            trim: true,
            required: 'Description is required'
        },
        articleBody: {
            type: String,
            trim: true,
            required: 'Main body is required'
        },
        imageId: {
            type: String,
            trim: true,
            default: null
        },
        user: {
            type: Schema.ObjectId,
            ref: "User",
            required: 'User is required',
            validate: {
                isAsync: true,
                validator: (v) => {
                    return FKHelper(mongoose.model("User"), v)
                },
                message: "User doesn't exist"
            }
        }
        tag: {
            type: String,
            trim: true,
        },
        updated: {
            type: Date,
            default: Date.now
        },
        created: {
            type: Date,
            default: Date.now
        },
        scheduled: {
            type: Date
        },
        published: {
            type: Date
        },
        isPublished: {
            type: Boolean,
            required: true,
            default: false
        }
    }
)

const CategorySchema = new mongoose.Schema(
    {
        name: {
            type: String,
            trim: true,
            required: 'Name is required'
        },
        alias: {
            type: String,
            trim: true,
            required: 'Alias is required'
        },
        description: {
            type: String,
            trim: true,
            default: null
        },
        imageId: {
            type: String,
            trim: true,
            default: null
        },
        parentcategory: {
            type: Schema.ObjectId,
            ref: "Category",
            validate: {
                isAsync: true,
                validator: (v) => {
                    return FKHelper(mongoose.model("Category"), v)
                },
                message: "Category doesn't exist"
            }
        },
        updated: {
            type: Date,
            default: Date.now
        },
        created: {
            type: Date,
            default: Date.now
        },
        isPublished: {
            type: Boolean,
            required: true,
            default: false
        }
    }
)

const ArticleCategorySchema = new mongoose.Schema(
    {
        category: {
            type: Schema.ObjectId,
            ref: "Category",
            validate: {
                isAsync: true,
                validator: (v) => {
                    return FKHelper(mongoose.model("Category"), v)
                },
                message: "Category doesn't exist"
            }
        },
        article: {
            type: Schema.ObjectId,
            ref: "Article",
            validate: {
                isAsync: true,
                validator: (v) => {
                    return FKHelper(mongoose.model("Article"), v)
                },
                message: "Article doesn't exist"
            }
        }
    }
)

💬 GPT-4:

Got it. So, we have:

  1. Article - represents individual articles.
  2. Category - represents categories, which can be hierarchical (a category can have a parent category).
  3. ArticleCategory - represents a many-to-many relationship between Article and Category (an article can belong to multiple categories and vice versa).

Now, let's create a few common queries based on these schemas:

  1. Find all articles in a specific category:

    const categoryId = ...; // Put the specific Category ID here
    const articlesInCategory = await ArticleCategory.find({ category: categoryId })
                                .populate('article')
                                .exec();
    
    const articles = articlesInCategory.map(ac => ac.article);
    
  2. Find all categories a specific article belongs to:

    const articleId = ...; // Put the specific Article ID here
    const categoriesForArticle = await ArticleCategory.find({ article: articleId })
                                .populate('category')
                                .exec();
    
    const categories = categoriesForArticle.map(ac => ac.category);
    
  3. Fetch all root categories (those without a parent category):

    const rootCategories = await Category.find({ parentcategory: null }).exec();
    
  4. Find all articles by a specific user:

    const userId = ...; // Put the specific User ID here
    const userArticles = await Article.find({ user: userId }).exec();
    
  5. Get articles scheduled for a specific date:

    const targetDate = ...; // Date in 'YYYY-MM-DD' format or a Date object
    const scheduledArticles = await Article.find({ 
      scheduled: new Date(targetDate) 
    }).exec();
    
  6. Retrieve all published categories (those marked as isPublished):

    const publishedCategories = await Category.find({ isPublished: true }).exec();
    

These are some basic queries to get you started. Depending on your needs, you may require more complex queries, especially when working with hierarchical data or doing deeper aggregation. Let me know if you have any specific questions or further queries you'd like to explore!

💬 ME: For the second query, I need an aggregated query that retrieves all categories associated with an article, using its ID. I only want to see the category name and the article title in the results. Additionally, only consider articles where 'isPublished' is set to true.

💬 GPT-4: Certainly! Aggregation is powerful for such tasks. Let's construct an aggregation pipeline for your requirement: If you want to retrieve categories only for articles that are marked as isPublished=true, you can add a filtering stage after joining with the Article collection. Here's the modified aggregation pipeline:

const articleId = ...;  // Replace with your specific Article ID

const pipeline = [
  {
    // Match the specific article by its ID in the ArticleCategory collection
    $match: { article: mongoose.Types.ObjectId(articleId) }
  },
  {
    // Join with the Article collection to get article details
    $lookup: {
      from: "articles",
      localField: "article",
      foreignField: "_id",
      as: "articleDetails"
    }
  },
  {
    $unwind: "$articleDetails"
  },
  {
    // Filter by articles that are published
    $match: { "articleDetails.isPublished": true }
  },
  {
    // Join with the Category collection to get category details
    $lookup: {
      from: "categories",
      localField: "category",
      foreignField: "_id",
      as: "categoryDetails"
    }
  },
  {
    $unwind: "$categoryDetails"
  },
  {
    // Project only the necessary fields
    $project: {
      _id: 0,
      articleTitle: "$articleDetails.title",
      categoryName: "$categoryDetails.name"
    }
  }
];

const results = await ArticleCategory.aggregate(pipeline).exec();
console.log(results);

In this pipeline:

  1. We first match the article by its ID.
  2. We then join with the Article collection to fetch article details.
  3. After unwinding the joined articleDetails, we filter the results further by checking if the isPublished field is true for the article.
  4. We then join with the Category collection to get category details.
  5. Lastly, we project only the necessary fields (article's title and category's name).

This will return categories only for the articles that have isPublished=true.

More to read


My New Plan: Making a Mini-Game Every Week
21/2/2025

This week, I realized that working on big projects can sometimes feel slow, and it’s easy to lose motivation. So, I came up with a new plan—I’ll create and release a small game every week!

Making Tic-Tac-Toe and Sudoku in Just a Few Hours
20/2/2025

This week, I decided to take a break from my main game project and create something simple: **a Tic-Tac-Toe and a Sudoku game**.

How I Made My Game Development Workflow Stress-Free
19/2/2025

Game development can be overwhelming, especially when working on multiple tasks without a clear plan. For a while, I was struggling to organize my thoughts and decide what to focus on next

Designing Fun and Engaging Game Levels
18/2/2025

Creating levels for a game sounds simple, but it comes with its own set of challenges.