Reputation: 587
So I have next Schema:
const CategorySchema = new Schema({
name: {
type: String,
required: true,
},
parent: {
type: Schema.Types.ObjectId,
ref: 'Category',
default: null,
},
order: {
type: Number,
required: true,
min: 0,
}
});
So what I would like is to get next output (I putted simple _ids just for simplicity of example):
[
{
_id: '1',
name: 'MainCategory1',
parent: null,
order: 0,
children: [
{
_id: '3',
name: 'SubCategory3',
parent: '1',
order: 0,
},
]
},
{
_id: '2',
name: 'MainCategory2',
parent: null,
order: 1,
children: [
{
_id: '4',
name: 'SubCategory1',
parent: '2',
order: 0,
},
{
_id: '5',
name: 'SubCategory2',
parent: '2',
order: 1,
},
]
},
]
So how could I get this result? Notice it has to be sorted by "order" field, for parents as well for children.
Also, is it possible to get this result with mongoose query, instead of aggregation?
I know this could be simpler if I stored "children" array in Schema, instead of "parent", but I like this approach better because each category has only one ref of parent, and doc doesn't get bloated with array of objectids. Other way around, "children" array could be really huge, and I think mongo works faster if it looks at one "parent" value when searching, instead of looking in array of "children", which could be 100+ elements of ObjectIds.
Upvotes: 2
Views: 936
Reputation: 49945
There's no way to use regular .find()
here but you can take advantage of Aggregation Framework's $graphLookup:
let Category = mongoose.model('Category', CategorySchema);
let result = await Category.aggregate([
{
$sort: { order: 1 }
},
{
$graphLookup: {
from: 'categories',
startWith: '$_id',
connectFromField: '_id',
connectToField: 'parent',
as: 'children'
}
},
{
$match: {
parent: null
}
}
]);
Upvotes: 3