We have nested categories for several products (e.g., Sports -> Basketball -> Men's, Sports -> Tennis -> Women's ) and are using Mongo instead of MySQL.

我们知道如何在MySQL这样的SQL数据库中存储嵌套的类别,但如果您能为Mongo提供建议,我们将不胜感激.我们需要优化的操作是快速查找一个类别或子类别中的所有产品,这些产品可以嵌套在根类别下的几层(例如,Men's Basketball类别中的所有产品或Women's Tennis类别中的所有产品).

This Mongo doc建议了一种方法,但它表示,当需要对子树进行操作时,它不起作用,而我们需要子树(因为类别可以达到多个级别).

关于高效存储和搜索任意深度嵌套类别的最佳方法,有什么建议吗?

推荐答案

你要决定的第一件事就是你要用什么样的树.

要考虑的最大问题是你的数据和访问模式.你已经说过,你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条,就这么简单.

希望它有意义,很长一段时间.

Mongodb相关问答推荐

MongoDB更新对象数组

MongoDB与合并对象聚合

带dropTarget的MongoDB renameCollection命令是原子的吗

获取响应周期中的特定键和值

如何在 MongoDB 中的集合下查找同一文档

mongoDB文档数组字段中的唯一项如何

分页时根据唯一字段mongodb获取数据

有没有办法从另一条记录中插入一条记录

Mongo:投影不影响布尔值

使用MongoDB作为我们的主数据库,我应该使用单独的图数据库来实现实体之间的关系吗?

MongoDB 存储大量指标/分析数据的方法

Ruby on Rails 的 Cassandra、mongodb 或 couchdb

使用 MongoDB 进行分页

MongoDB - 投影一个并不总是存在的字段

MongoDb:如何将附加对象插入对象集合?

mongoose:按字母顺序排序

在 Ubuntu 13.10 (saucy) 中安装 Mongodb PHP 扩展的最简单方法?

全局初始化失败:BadValue Invalid or no user locale set.请确保正确设置 LANG 和/或 LC_* 环境变量

创建模型时出现mongoose错误

将 FilterDefinition 转换为可以在 mongo shell 中运行的常规 json mongo 查询