I have a category Model which looks like this
const mongoose = require("mongoose");
const { Schema } = mongoose;
const { ObjectId } = Schema;
const category = {
name: {
type: String,
required: true,
trim: true,
max: 32,
unique: true,
},
subCategories: [
{
type: Schema.Types.ObjectId,
ref: "Category",
},
],
parent: {
type: Schema.Types.ObjectId,
ref: "Category",
},
products: [
{
type: ObjectId,
ref: "Product",
},
],
slug: {
type: String,
required: "URL can't be empty",
unique: true,
},
};
const categorySchema = new Schema(category, { timestamps: true });
//Validate the slug to ensure proper url is given
categorySchema.path("slug").validate((val) => {
urlRegex =
/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/;
return urlRegex.test(val);
}, "Invalid URL.");
const autoPopulateChildren = function (next) {
this.populate("subCategories");
next();
};
categorySchema
.pre("findOne", autoPopulateChildren)
.pre("findById", autoPopulateChildren)
.pre("find", autoPopulateChildren);
const Category = mongoose.model("Category", categorySchema);
module.exports = Category;
I would like to recursively populate its parent.
Right now, I have a data that looks like this
Main
-> Computers & Accessories
-> Components
-> Motherboard
When I query Motherboard category, I would like it to return back all its parents (all the way up to Main category). Something like this
{
"subCategories": [],
"products": [],
"_id": "62baca1a1ffdc142085bca80",
"name": "Motherboard",
"parent": {
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62baca1a1ffdc142085bca80",
"name": "Motherboard",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/motherboard",
"createdAt": "2022-06-28T09:30:02.040Z",
"updatedAt": "2022-06-28T09:30:02.040Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bac9a24bd73045dcb563d7",
"name": "RAM",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/ram",
"createdAt": "2022-06-28T09:28:02.643Z",
"updatedAt": "2022-06-28T09:28:02.643Z",
"__v": 0
}
],
"products": [],
"_id": "62bac5af6b6581786cb192e4",
"name": "components",
"parent": {
"subCategories": [
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62baca1a1ffdc142085bca80",
"name": "Motherboard",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/motherboard",
"createdAt": "2022-06-28T09:30:02.040Z",
"updatedAt": "2022-06-28T09:30:02.040Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bac9a24bd73045dcb563d7",
"name": "RAM",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/ram",
"createdAt": "2022-06-28T09:28:02.643Z",
"updatedAt": "2022-06-28T09:28:02.643Z",
"__v": 0
}
],
"products": [],
"_id": "62bac5af6b6581786cb192e4",
"name": "components",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007/category/components",
"createdAt": "2022-06-28T09:11:11.226Z",
"updatedAt": "2022-06-28T09:11:11.226Z",
"__v": 0
},
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62bacae4da4c372c48c4a996",
"name": "Huawei",
"parent": "62bac6696b6581786cb192e7",
"slug": "http://localhost:4007/category/huawei",
"createdAt": "2022-06-28T09:33:24.218Z",
"updatedAt": "2022-06-28T09:33:24.218Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bacb137e6e0b6ac850b9ce",
"name": "Apple",
"parent": "62bac6696b6581786cb192e7",
"slug": "http://localhost:4007/category/apple",
"createdAt": "2022-06-28T09:34:11.549Z",
"updatedAt": "2022-06-28T09:34:11.549Z",
"__v": 0
}
],
"products": [],
"_id": "62bac6696b6581786cb192e7",
"name": "laptop",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007//category/laptop",
"createdAt": "2022-06-28T09:14:17.650Z",
"updatedAt": "2022-06-28T09:14:17.650Z",
"__v": 0
},
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62bacb65045848303cd21b67",
"name": "Gaming",
"parent": "62bac8016b6581786cb192f0",
"slug": "http://localhost:4007/category/gaming",
"createdAt": "2022-06-28T09:35:33.414Z",
"updatedAt": "2022-06-28T09:35:33.414Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bacc72e84e007314a97abe",
"name": "DIY",
"parent": "62bac8016b6581786cb192f0",
"slug": "http://localhost:4007/category/diy",
"createdAt": "2022-06-28T09:40:02.359Z",
"updatedAt": "2022-06-28T09:40:02.359Z",
"__v": 0
}
],
"products": [],
"_id": "62bac8016b6581786cb192f0",
"name": "Desktop",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007//category/components",
"createdAt": "2022-06-28T09:21:05.807Z",
"updatedAt": "2022-06-28T09:21:05.807Z",
"__v": 0
}
],
"products": [],
"_id": "62bac35ba30786989841809b",
"name": "Computers & Accessories",
"parent": {
"subCategories": [
{
"subCategories": [
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62baca1a1ffdc142085bca80",
"name": "Motherboard",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/motherboard",
"createdAt": "2022-06-28T09:30:02.040Z",
"updatedAt": "2022-06-28T09:30:02.040Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bac9a24bd73045dcb563d7",
"name": "RAM",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/ram",
"createdAt": "2022-06-28T09:28:02.643Z",
"updatedAt": "2022-06-28T09:28:02.643Z",
"__v": 0
}
],
"products": [],
"_id": "62bac5af6b6581786cb192e4",
"name": "components",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007/category/components",
"createdAt": "2022-06-28T09:11:11.226Z",
"updatedAt": "2022-06-28T09:11:11.226Z",
"__v": 0
},
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62bacae4da4c372c48c4a996",
"name": "Huawei",
"parent": "62bac6696b6581786cb192e7",
"slug": "http://localhost:4007/category/huawei",
"createdAt": "2022-06-28T09:33:24.218Z",
"updatedAt": "2022-06-28T09:33:24.218Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bacb137e6e0b6ac850b9ce",
"name": "Apple",
"parent": "62bac6696b6581786cb192e7",
"slug": "http://localhost:4007/category/apple",
"createdAt": "2022-06-28T09:34:11.549Z",
"updatedAt": "2022-06-28T09:34:11.549Z",
"__v": 0
}
],
"products": [],
"_id": "62bac6696b6581786cb192e7",
"name": "laptop",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007//category/laptop",
"createdAt": "2022-06-28T09:14:17.650Z",
"updatedAt": "2022-06-28T09:14:17.650Z",
"__v": 0
},
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62bacb65045848303cd21b67",
"name": "Gaming",
"parent": "62bac8016b6581786cb192f0",
"slug": "http://localhost:4007/category/gaming",
"createdAt": "2022-06-28T09:35:33.414Z",
"updatedAt": "2022-06-28T09:35:33.414Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bacc72e84e007314a97abe",
"name": "DIY",
"parent": "62bac8016b6581786cb192f0",
"slug": "http://localhost:4007/category/diy",
"createdAt": "2022-06-28T09:40:02.359Z",
"updatedAt": "2022-06-28T09:40:02.359Z",
"__v": 0
}
],
"products": [],
"_id": "62bac8016b6581786cb192f0",
"name": "Desktop",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007//category/components",
"createdAt": "2022-06-28T09:21:05.807Z",
"updatedAt": "2022-06-28T09:21:05.807Z",
"__v": 0
}
],
"products": [],
"_id": "62bac35ba30786989841809b",
"name": "Computers & Accessories",
"parent": "62bac6eddfe90a7c09873d92",
"slug": "http://localhost:4007/category/computers&accessories",
"createdAt": "2022-06-28T09:01:15.666Z",
"updatedAt": "2022-06-28T09:01:15.666Z",
"__v": 0
}
],
"products": [],
"_id": "62bac6eddfe90a7c09873d92",
"name": "Main Shop Name",
"parent": null,
"slug": "http://localhost:4007/category/main",
"createdAt": "2022-06-28T09:01:15.666Z",
"updatedAt": "2022-06-28T09:01:15.666Z",
"__v": 0
},
"slug": "http://localhost:4007/category/computers&accessories",
"createdAt": "2022-06-28T09:01:15.666Z",
"updatedAt": "2022-06-28T09:01:15.666Z",
"__v": 0
},
"slug": "http://localhost:4007/category/components",
"createdAt": "2022-06-28T09:11:11.226Z",
"updatedAt": "2022-06-28T09:11:11.226Z",
"__v": 0
},
"slug": "http://localhost:4007/category/motherboard",
"createdAt": "2022-06-28T09:30:02.040Z",
"updatedAt": "2022-06-28T09:30:02.040Z",
"__v": 0
}
Following is my code
const populateParents = async (node) => {
if (node.parent) {
let newNode = await Category.populate(node, { path: "parent" });
return populateParents(newNode.parent);
}
return node;
};
//Routes
router.get("/categories/:categoryId", [RequireSignIn], async (req, res) => {
try {
const { categoryId } = req.params;
const category = await Category.findOne({ _id: categoryId });
const populatedCategories = await populateParents(category);
return res.status(200).send(populatedCategories);
} catch (error) {
return res.status(500).send(error);
}
});
What I am getting back is only the Main category in response.
{
"subCategories": [
{
"subCategories": [
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62baca1a1ffdc142085bca80",
"name": "Motherboard",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/motherboard",
"createdAt": "2022-06-28T09:30:02.040Z",
"updatedAt": "2022-06-28T09:30:02.040Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bac9a24bd73045dcb563d7",
"name": "RAM",
"parent": "62bac5af6b6581786cb192e4",
"slug": "http://localhost:4007/category/ram",
"createdAt": "2022-06-28T09:28:02.643Z",
"updatedAt": "2022-06-28T09:28:02.643Z",
"__v": 0
}
],
"products": [],
"_id": "62bac5af6b6581786cb192e4",
"name": "components",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007/category/components",
"createdAt": "2022-06-28T09:11:11.226Z",
"updatedAt": "2022-06-28T09:11:11.226Z",
"__v": 0
},
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62bacae4da4c372c48c4a996",
"name": "Huawei",
"parent": "62bac6696b6581786cb192e7",
"slug": "http://localhost:4007/category/huawei",
"createdAt": "2022-06-28T09:33:24.218Z",
"updatedAt": "2022-06-28T09:33:24.218Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bacb137e6e0b6ac850b9ce",
"name": "Apple",
"parent": "62bac6696b6581786cb192e7",
"slug": "http://localhost:4007/category/apple",
"createdAt": "2022-06-28T09:34:11.549Z",
"updatedAt": "2022-06-28T09:34:11.549Z",
"__v": 0
}
],
"products": [],
"_id": "62bac6696b6581786cb192e7",
"name": "laptop",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007//category/laptop",
"createdAt": "2022-06-28T09:14:17.650Z",
"updatedAt": "2022-06-28T09:14:17.650Z",
"__v": 0
},
{
"subCategories": [
{
"subCategories": [],
"products": [],
"_id": "62bacb65045848303cd21b67",
"name": "Gaming",
"parent": "62bac8016b6581786cb192f0",
"slug": "http://localhost:4007/category/gaming",
"createdAt": "2022-06-28T09:35:33.414Z",
"updatedAt": "2022-06-28T09:35:33.414Z",
"__v": 0
},
{
"subCategories": [],
"products": [],
"_id": "62bacc72e84e007314a97abe",
"name": "DIY",
"parent": "62bac8016b6581786cb192f0",
"slug": "http://localhost:4007/category/diy",
"createdAt": "2022-06-28T09:40:02.359Z",
"updatedAt": "2022-06-28T09:40:02.359Z",
"__v": 0
}
],
"products": [],
"_id": "62bac8016b6581786cb192f0",
"name": "Desktop",
"parent": "62bac35ba30786989841809b",
"slug": "http://localhost:4007//category/components",
"createdAt": "2022-06-28T09:21:05.807Z",
"updatedAt": "2022-06-28T09:21:05.807Z",
"__v": 0
}
],
"products": [],
"_id": "62bac35ba30786989841809b",
"name": "Computers & Accessories",
"parent": "62bac6eddfe90a7c09873d92",
"slug": "http://localhost:4007/category/computers&accessories",
"createdAt": "2022-06-28T09:01:15.666Z",
"updatedAt": "2022-06-28T09:01:15.666Z",
"__v": 0
}
],
"products": [],
"_id": "62bac6eddfe90a7c09873d92",
"name": "Main Shop Name",
"parent": null,
"slug": "http://localhost:4007/category/main",
"createdAt": "2022-06-28T09:01:15.666Z",
"updatedAt": "2022-06-28T09:01:15.666Z",
"__v": 0
}
If I write the function without recursion , it works
const populateParents2 = async (node) => {
const newNode = await Category.populate(node, { path: "parent" });
const newNode2 = await Category.populate(newNode.parent, { path: "parent" });
const newNode3 = await Category.populate(newNode2.parent, { path: "parent" });
return newNode;
};
So appreciate if someone can point out how to write populateParents function recursively or is there another better way to do this
Thank you