你要决定的第一件事就是你要用什么样的树.
要考虑的最大问题是你的数据和访问模式.你已经说过,你90%的工作都是查询的,而且听上go (Electron 商务)更新只会由管理员运行,很可能很少.
So you want a schema that gives you the power of querying quickly on child through a path, i.e.: Sports -> Basketball -> Men's, Sports -> Tennis -> Women's, and doesn't really need to truly scale to updates.
正如您正确指出的那样,MongoDB确实有一个很好的文档页面:https://docs.mongodb.com/manual/applications/data-models-tree-structures/其中,10gen实际上陈述了树的不同模型和模式方法,并描述了它们的主要起伏.
如果你想轻松地进行查询,那么应该注意的一个问题是具体化路径:https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/
这是一种非常有趣的方法来建立树,因为要在"网球"中查询您在上面给出的示例中的"Women",您只需执行一个预先固定的正则表达式(可以使用索引:http://docs.mongodb.org/manual/reference/operator/regex/),如下所示:
db.products.find({category: /^Sports,Tennis,Womens[,]/})
查找树的特定路径下列出的所有产品.
不幸的是,这种模式在更新方面非常糟糕,如果你移动一个类别或更改其名称,你必须更新所有产品,一个类别下可能有数千种产品.
更好的方法是在产品上放置一个cat_id
,然后使用模式将类别划分为一个单独的集合:
{
_id: ObjectId(),
name: 'Women\'s',
path: 'Sports,Tennis,Womens',
normed_name: 'all_special_chars_and_spaces_and_case_senstive_letters_taken_out_like_this'
}
因此,现在您的查询只涉及categories集合,这将使它们更小、更高效.例外情况是,当你删除一个类别时,产品仍然需要touch .
因此,将"网球"改为"羽毛球"的一个例子是:
db.categories.update({path:/^Sports,Tennis[,]/}).forEach(function(doc){
doc.path = doc.path.replace(/,Tennis/, ",Badmin");
db.categories.save(doc);
});
不幸的是,MongoDB目前没有提供查询内文档反射,因此您必须将它们从客户端拉出,这有点烦人,但希望它不会导致返回太多类别.
这就是它的工作原理.更新有点痛苦,但使用索引在任何路径上即时查询的能力更适合您的场景,我相信.
当然,这个模式还有一个额外的好处,那就是它与嵌套的集合模型兼容:http://en.wikipedia.org/wiki/Nested_set_model我一次又一次地发现,对于Electron 商务网站来说,http://en.wikipedia.org/wiki/Nested_set_model非常棒.例如,网球可能同时属于"运动"和"休闲"两类,你需要多条路径,这取决于用户来自哪里.
物质化路径的模式很容易支持这一点,只需再增加path
条,就这么简单.
希望它有意义,很长一段时间.