skip to Main Content
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;

const productSchema = new mongoose.Schema(
  {
    title: {
      type: String,
      trim: true,
      required: true,
      maxlength: 32,
      text: true,
    }, 
  
    category: {
      type: ObjectId,
      ref: "Category",
    },

)

I am tring to filter products based on category name, but cateogry itself is a different collection. How can I apply filter conditions correctly as current one is not working.

 const products = await Product.find({ title:title, "category.name": categ})
const categorySchema = new mongoose.Schema(
  {
    name: {
      type: String,
      trim: true,
      required: "Name is required",
      minlength: [2, "Too short"],
      maxlength: [32, "Too long"],
    },
    
  { timestamps: true }
);

2

Answers


  1. To get access to category.name you need to use the populate method. However, because you are using referenced docs, which is a perfectly good design for your schemas, it unfortunately means that you can’t filter parent documents based on a condition of a referenced child document as per the docs

    In general, there is no way to make populate() filter stories based on properties of the story’s author. For example, the below query won’t return any results, even though author is populated. If you want to filter stories by their author’s name, you should use denormalization.

    Thankfully you can use aggregate() to get what you need.

    The mongoose Model.aggregate method allows you to pass mongodb aggregation pipeline stages. This can be used in your case to populate all of your Product documents with their referenced Category documents. Then once they are embedded you can then match on category.name like so:

    const products = await Product.aggregate([
      {
        $match: { //< Find the products that match your title search
          "title": title 
        }
      },
      {
        $lookup: {  //< Now populate the categories
          from: "categories", 
          localField: "category",
          foreignField: "_id",
          as: "category"
        }
      },
      {
        $match: { //< Only return matches on the category.name
          "category.name": categ
        }
      }
    ]);
    

    See HERE for a working example where a user searches for the Product title:'Hat' from the Category of name:'Mens'.

    Login or Signup to reply.
  2. I think you can use populate to get values from your query. Just update the query as per below.

    const products = await Product.find({ title:title}).populate({
         path:"category" , //name of foriegn table field here category in your productSchema
         match : { "name" : "value"} // name of the field in categorySchema 
    })
    

    or else you can use aggregation pipeline solve but i think populate will be more performant way to solve question.You can also define virtuals for populate that makes easy your task.

    refer to similer Question

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search