Wolfdog
Wolfdog

Reputation: 587

MongoDB List categories children in parent category

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

Answers (1)

mickl
mickl

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

Related Questions