ChatGPT to the Rescue: Tackling a Coding Challenge Together!

ChatGPT to the Rescue: Tackling a Coding Challenge Together!

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