I have these two mongoose documents
[
{
"_id": "63a7b67b333394043fdca934",
"name": "Macbook M2 PRO",
"category": [
"62bacb137e6e0b6ac850b9ce",
"63a7b5bb333394043fdca923"
],
"avgRating": 5,
"price": 5000.95,
"slug": "macbook-pro-m2",
"images": [
{
"_id": "63a7b67b333394043fdca935",
"public_id": "ecommerce/1671935608704",
"url": "xxx"
},
..
],
"color": [
"White",
"Silver"
],
"description": "The 13-inch MacBook Pro is more capable than ever. Supercharged by the next-generation M2 chip, it’s Apple’s most portable pro laptop, with up to 20 hours of battery life.",
"ratings": [
{
"_id": "63fc7c670a3b7a0824c4b4ba",
"star": 5,
"postedBy": "6241b32d8b01924f5c75cd85"
}
],
"sold": 0
},
{
"_id": "63a7b280333394043fdca8fb",
"name": "Ipad Pro",
"category": [
"63a7b1c0333394043fdca8ea",
"62bacb137e6e0b6ac850b9ce"
],
"avgRating": 4,
"price": 3000.54,
"slug": "ipad-pro",
"images": [
{
"_id": "63a7b280333394043fdca8fc",
"public_id": "ecommerce/1671934588743",
"url": "xxx"
},
...
],
"color": [
"White",
"Silver"
],
"description": "Just another Ipad",
"ratings": [
{
"_id": "63fc05ee981f4c0b61dc8c89",
"star": 5,
"postedBy": "6241b25f8b01924f5c75cd82"
},
...
],
"sold": 0
}
]
I would like to filter out the document with the category in "62bacb137e6e0b6ac850b9ce", "63a7b5bb333394043fdca923" . Basically a where in clause, document where the category ids matches both the category ids above.
So this is what I did but does not work
const product = await Product.aggregate([
{
$match: {
$text: { $search: `"${searchText}"` },
},
},
{
$addFields: {
root: "$$ROOT",
},
},
{
$project: {
name: "$root.name",
// category: "$root.category", //this will give a list of categories
category: {
$filter: {
input: "$root.category",
as: "category",
cond: { $in: ["62bacb137e6e0b6ac850b9ce" , "63a7b5bb333394043fdca923"] },
},
},
avgRating: {
$floor: { $avg: "$ratings.star" },
},
price: "$root.price",
slug: "$root.slug",
images: "$root.images",
color: "$root.color",
description: "$root.description",
ratings: "$root.ratings",
sold: "$root.sold",
},
},
]);
my product Model
const product = {
name: {
type: String,
required: true,
trim: true,
minlength: [2, "Too short"],
maxlength: [32, "Too long"],
unique: true,
},
slug: {
type: String,
unique: true,
lowercase: true,
index: true,
},
category: [
{
type: ObjectId,
ref: "Category",
},
],
description: {
type: String,
maxlength: 200,
},
price: {
type: Number,
required: true,
trim: true,
maxlength: 32,
},
shipping: {
type: String,
enum: ["Yes", "No"],
},
color: [
{
type: String,
enum: ["Black", "Brown", "Silver", "White", "Blue"],
},
],
sold: {
type: Number,
default: 0,
},
quantity: {
type: Number,
},
images: [
{
public_id: String,
url: String,
},
],
ratings: [
{
star: Number,
postedBy: {
type: ObjectId,
ref: "User",
},
},
],
};
const productSchema = new Schema(product, { timestamps: true });
productSchema.index({ name: 1, category: 1 });
So I just found the answer from this post , Can I use $in within mongodb's $match aggregate function
Basically normal string does not work. We have to convert it to Mongodb object string. So this is what I did
const ObjectId = require("mongodb").ObjectID;
const product = await Product.aggregate([
{
$match: {
$text: { $search: `"${searchText}"` },
price: 3000.54,
category: {
$in: [ObjectId("62bacb137e6e0b6ac850b9ce") , ObjectId
('63a7b5bb333394043fdca923')],
},
},
},
{
$addFields: {
root: "$$ROOT",
},
},
{
$project: {
name: "$root.name",
category: "$root.category", //this will give a list of categories
avgRating: {
$floor: { $avg: "$ratings.star" },
},
price: "$root.price",
slug: "$root.slug",
images: "$root.images",
color: "$root.color",
description: "$root.description",
ratings: "$root.ratings",
sold: "$root.sold",
},
}
]);
Thank you