使用mongodb和nodejs的类别层次结构聚合

时间:2015-02-13 03:43:43

标签: node.js mongodb hierarchy

我的文档结构如下:

{
    "_id" : ObjectId("54d81827e4a4449d023b4e34"),
    "cat_id" : 1,
    "description" : "Refridgerator",
    "image" : "refridgerator",
    "parent" : null,
    "slug" : "refridgerator"
}
{
    "_id" : ObjectId("54dc38bce4a4449d023b4e58"),
    "name" : "Ice Cream",
    "description" : "Ice Cream",
    "image" : "ice-cream.jpg",
    "slug" : "ice-cream",
    "parent" : "54d81827e4a4449d023b4e34"
}
{
    "_id" : ObjectId("54dc3705e4a4449d023b4e56"),
    "name" : "Chocolate",
    "description" : "Chocolate",
    "image" : "chocolate.jpg",
    "slug" : "chocolate",
    "parent" : "54d81827e4a4449d023b4e34"
}

我正在使用mongodb和nodejs创建一个类别层次结构。

现在我希望查询_id = ‘54d81827e4a4449d023b4e34’(Refridgerator)并应该取回所有子类别

如何在nodejs中实现上述目标?

此外,nodejs使用对数据库的异步调用,我无法通过父子关系获得json结构。

我如何为此进行异步调用?

2 个答案:

答案 0 :(得分:2)

这与NodeJS无关,重要的是你的数据结构。

参考我对this question的回答,第一部分是关于如何有效实施它。

答案 1 :(得分:2)

你想要冰箱和所有子类别吗?

异步也是一个问题吗?

我认为你可以在这里使用聚合。

假设您正在寻找一个_id变量的类别,该变量是您想要的ObjectId及其子类别。

db.yourCollection.aggregate({
    // get stuff where you have the parent or subcats.
    $match: {
         $or: [
               {_id: ObjectId("54de8b9f022ff38bbf5e0530")},
               {parent: ObjectId("54de8b9f022ff38bbf5e0530")}
              ]
         }
},
// reshape the data you'll need further on from each mached doc
{
    $project: {
        _id: false,
        data: {
            id: '$_id',
            name: '$name'
            // I guess you'll also want the `slug` and `image` here.
            // but that's homework :)
        },
        parent: '$parent'
    }
},
// now put a common _id so you can group them, and also put stuff into arrays
{
    $project: {
        id: {$literal: 'id'},
        mainCategory: {
            // if our parent is null, put our data.
            // otherwise put null here.
            $cond: [{$eq: [null, '$parent']}, {_id: '$data.id', name: '$data.name'}, undefined]
        },
        subcat: {
            // here is the other way around.
            $cond: [{$ne: [null, '$parent']}, {_id: '$data.id', name: '$data.name'}, null]

        }
    }
    // that stage produces for each doc either a mainCat or subcat
    // (and the other prop equals to null)
},
// finally, group the things so you can have them together
{
    $group: {
        _id: '$id',
        // a bit hacky, but mongo will yield to it
        mainCategory: {$max: '$mainCategory'},
        subCategories: {
            // this will, unfortunately, also add the `null` we have
            // assigned to main category up there
            $addToSet: '$subcat'
        }
    }
},
// so we get rid of the unwanted _id = 'id' and the null from subcats.
{
    $project: {
        _id: false,
        mainCategory: 1,
        subCategories: {
            $setDifference: ['$subCategories', [null]]
        }
    }
})

鉴于此数据集:

[{
    "_id" : ObjectId("54de8b9f022ff38bbf5e0530"),
    "name" : "Fridge",
    "parent" : null
},
{
    "_id" : ObjectId("54de8bba022ff38bbf5e0531"),
    "name" : "choco",
    "parent" : ObjectId("54de8b9f022ff38bbf5e0530")
},
{
    "_id" : ObjectId("54de8bc8022ff38bbf5e0532"),
    "name" : "apple",
    "parent" : ObjectId("54de8b9f022ff38bbf5e0530")
}

我得到了这个结果:

{
    "result" : [ 
        {
            "mainCategory" : {
                "_id" : ObjectId("54de8b9f022ff38bbf5e0530"),
                "name" : "Fridge"
            },
            "subCategories" : [ 
                {
                    "_id" : ObjectId("54de8bc8022ff38bbf5e0532"),
                    "name" : "apple"
                }, 
                {
                    "_id" : ObjectId("54de8bba022ff38bbf5e0531"),
                    "name" : "choco"
                }
            ]
        }
    ],
    "ok" : 1
}

至于异步,通常你会做这样的事情:

db.collection.aggregate(thePipeLineAbove, function(err, results) {

    // handle err
    if (err) {
       // deal with it
    } else {
        console.log(results);
    }
});

但这取决于您的MongoDB驱动程序。

即使你有更深层次的结构,你也可以扩展它。