您要决定的第一件事就是您将使用哪种树。
需要考虑的最重要的事情是您的数据和访问模式。您已经说过,您所有工作的 90% 都将是查询,并且听起来(电子商务)更新将仅由管理员运行,很可能很少。
因此,您需要一个架构,使您能够通过路径(即:体育 -> 篮球 -> 男子、体育 -> 网球 -> 女子)快速查询子项,并且实际上不需要真正扩展以更新。
正如您正确指出的那样,MongoDB 确实有一个很好的文档页面:https://docs.mongodb.com/manual/applications/data-models-tree-structs/ https://docs.mongodb.com/manual/applications/data-models-tree-structures/10gen 实际上陈述了树的不同模型和模式方法,并描述了它们的主要优点和缺点。
如果您希望轻松查询,应该引起注意的是物化路径:https://docs.mongodb.com/manual/tutorial/model-tree-structs-with-materialized-paths/ https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/
这是一种非常有趣的构建树的方法,因为要查询上面给出的“网球”中“女性”的示例,您可以简单地执行一个预先固定的正则表达式(可以使用索引:http://docs.mongodb.org/manual/reference/operator/regex/ 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'
}
因此,现在您的查询仅涉及类别集合,这应该使它们更小且性能更高。例外情况是,当您删除类别时,产品仍然需要触摸。
将“网球”更改为“羽毛球”的示例:
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 http://en.wikipedia.org/wiki/Nested_set_model我一次又一次地发现这对于电子商务网站来说非常棒,例如,网球可能同时位于“体育”和“休闲”下,并且您需要根据用户来自哪里的多个路径。
物化路径的模式只需添加另一个即可轻松支持这一点path
,就这么简单。
希望它有意义,那里很长。