- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我们为多个产品(例如,体育 -> 篮球 -> 男装、体育 -> 网球 -> 女装)嵌套了类别,并且使用 Mongo 而不是 MySQL .
我们知道如何在 MySQL 等 SQL 数据库中存储嵌套类别,但如果您能就如何为 Mongo 提供任何建议,我们将不胜感激。我们需要优化的操作是快速找到一个类别或子类别中的所有产品,这些产品可以嵌套在一个根类别之下的几层(例如,Men's Basketball 类别中的所有产品或女子网球类别)。
This Mongo doc建议了一种方法,但它表示当我们需要对子树进行操作时它效果不佳(因为类别可以达到多个级别)。
关于有效存储和搜索任意深度嵌套类别的最佳方法有什么建议吗?
最佳答案
您首先要决定的是您将使用哪种树。
要考虑的最重要的事情是您的数据和访问模式。您已经说过,您所有工作的 90% 都将是查询,并且听起来(电子商务)更新只会由管理员运行,而且很可能很少。
因此,您需要一个模式,让您能够通过路径快速查询 child ,即:体育 -> 篮球 -> 男子、体育 -> 网球 -> 女子,并且不需要真正扩展到更新。
正如您正确指出的那样,MongoDB 确实为此提供了一个很好的文档页面:https://docs.mongodb.com/manual/applications/data-models-tree-structures/从而 10gen 实际上为树陈述了不同的模型和模式方法,并描述了它们的主要起伏。
如果您希望轻松查询,应该引起注意的是具体化路径:https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/
这是一种非常有趣的构建树的方法,因为要在上面给出的示例中查询“网球”中的“女性”,您可以简单地执行一个预先固定的正则表达式(可以使用索引: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'
}
所以现在您的查询只涉及类别集合,这应该会使它们更小且性能更高。异常(exception)情况是当您删除一个类别时,产品仍需要触摸。
所以一个把“网球”改成“羽毛球”的例子:
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我一次又一次地发现这对于电子商务网站来说非常棒,例如,网球可能同时属于“体育”和“休闲”,并且您需要多个路径,具体取决于用户来自哪里。
物化路径的架构很容易支持这一点,只需添加另一个 path
,就这么简单。
希望它是有道理的,那里很长。
关于mongodb - 在 Mongo 中存储嵌套类别(或分层数据)的最有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14966777/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!