我用MongoDB和Mongoose制作父母参考树。我的架构看起来像这样
var NodesSchema = new Schema({
_id: {
type: ShortId,
len: 7
},
name: { // name of the file or folder
type: String,
required: true
},
isFile: { // is the node file or folder
type: Boolean,
required: true
},
location: { // location, null for root
type: ShortId,
default: null
},
data: { // optional if isFile is true
type: String
}
});
请注意,文件/文件夹可重命名。
在我当前的设置中,如果我想获取特定文件夹中的文件,请执行以下查询:
NodesModel.find({ location: 'LOCATION_ID' })
如果我想获得一个文件/文件夹我运行:
NodesModel.findOne({ _id: 'ITEM_ID' })
并且位置字段看起来像f8mNslZ1
但是如果我想获取位置文件夹名称,我需要进行第二次查询。
不幸的是,如果我想获取root的路径,我需要进行递归查询,如果我有300个嵌套文件夹,这可能会很慢。
所以我一直在寻找并找出以下可能的解决方案:
我应该将位置字段从字符串更改为对象,并将信息保存在其中,如下所示:
location: {
_id: 'LOCATION_ID',
name: 'LOCATION_NAME',
fullpath: '/FOLDERNAME1/FOLDERNAME2'
}
此解决方案中的问题是文件/文件夹可重命名。在重命名时,我应该更新所有孩子。然而,重命名很少发生,然后索引,但如果文件夹有1000个项目,我想是一个问题。
我的问题是:
答案 0 :(得分:4)
查看您的节点架构,如果您将location
属性更改为对象,您将有2个位置,您可以在其中声明节点的名称,因此请注意更新这两个名称属性。通常,您希望尽可能将数据库保留为DRY,并且在大多数情况下,执行嵌套查询非常常见。话虽如此,您比我更了解您的数据库,如果您通过执行更多查询看到显着的性能延迟,那么请务必更新所有名称属性。
除此之外,如果您的位置的fullpath
属性是一个字符串,并且假设您遇到必须重命名文件夹的情况,则必须通过破坏来分析整个字符串它将子字符串与新文件夹名称的新值进行比较。这可能会变得单调乏味。
一种可能的解决方案是将完整路径存储为数组而不是字符串,将订单作为链中的下一个文件夹,这样您就可以在需要时快速进行比较和更新。
答案 1 :(得分:1)
对树结构进行建模的不同方法是extensively covered in the MongoDB docs。
你提出的方式就是其中之一。
根据预期发生文件夹重命名的频率(和/或任何其他层次结构更改比添加新叶节点更复杂),您可以考虑将“路径”存储为“祖先数组”。但无论你采用哪种方式对每个文件夹中的树进行非规范化或具体化,那么权衡就是为了加快查找速度,你会得到更慢和/或更复杂的更新。
在你的情况下,优化读取而不是罕见的更新似乎很清楚 - 除了不那么频繁之外,似乎可以异步完成重命名,而在显示父文件夹名称时根本不可能。
虽然DRY是编程中的一个很好的原则,但它几乎不适用于非关系数据库,所以除非你使用严格的关系数据库和普通形式,否则不要将它应用于你的模式设计,事实上这将是特别在MongoDB中不鼓励,因为那时你会使用错误的工具来完成工作。