Node.js 我应该如何为嵌套文档建模MongoDB集合?

Node.js 我应该如何为嵌套文档建模MongoDB集合?,node.js,mongodb,database-design,nosql,Node.js,Mongodb,Database Design,Nosql,我正在为一家建筑产品商店管理MongoDB数据库。最直接的收藏是产品,对吗? 有相当多的产品,但它们都属于一组5-8个类别中的一个,然后属于一小组子类别中的一个子类别 例如: -Electrical *Wires p1 p2 .. *Tools p5 pn .. *Sockets p11 p23 .. -Plumber *Pipes .. *Tools .. PVC .. {

我正在为一家建筑产品商店管理MongoDB数据库。最直接的收藏是产品,对吗? 有相当多的产品,但它们都属于一组5-8个类别中的一个,然后属于一小组子类别中的一个子类别

例如:

-Electrical
  *Wires
    p1
    p2
    ..
  *Tools
    p5
    pn
    ..
  *Sockets
    p11
    p23
    ..
-Plumber
  *Pipes
    ..
  *Tools
    ..
  PVC
    ..
{
    ... // other fields of product
    categories: [100, 101, 102, ...]
}
我将在web站点客户端使用Angular来显示整个产品目录,我考虑使用AJAX来查询我想要的产品的正确子集

然后,我想知道我是否应该只管理一个集合,如:

{
    
    MainCategory1: {


        SubCategory1: {
        {},{},{},{},{},{},{}
        }
        SubCategory2: {
        {},{},{},{},{},{},{}
        }
        SubCategoryn: {
        {},{},{},{},{},{},{}
        }               
    },
    MainCategory2: {


        SubCategory1: {
        {},{},{},{},{},{},{}
        }
        SubCategory2: {
        {},{},{},{},{},{},{}
        }
        SubCategoryn: {
        {},{},{},{},{},{},{}
        }               
    },  
    MainCategoryn: {


        SubCategory1: {
        {},{},{},{},{},{},{}
        }
        SubCategory2: {
        {},{},{},{},{},{},{}
        }
        SubCategoryn: {
        {},{},{},{},{},{},{}
        }               
    }   
}
或每个类别的单个集合。文档的数量可能不超过500个。但是,我关心以下方面的平衡:

  • 快速回答
  • 方便的服务器端数据库查询,以及
  • 用于将结果呈现为html的客户端代码
我现在用的是猫鼬,不是猫鼬

我将执行哪些CRUD操作?
  • 插入产品,我还希望有一种方法可以获得每个新寄存器的自动生成ID(可能是顺序的)。然而,由于这似乎很自然,我不会向用户提供\u id

  • 查询子类别的整个文档集。也许刚开始只是获得一些属性

  • 查询文档(产品)的全部或特定属性子集

  • 修改产品的属性


我同意客户端应该得到最容易呈现的结果。然而,将类别嵌套到产品中仍然是一个坏主意。取舍是一旦你想要改变,例如,一个类别的名称,那将是一场灾难。如果您考虑可能的用例,例如:

-Electrical
  *Wires
    p1
    p2
    ..
  *Tools
    p5
    pn
    ..
  *Sockets
    p11
    p23
    ..
-Plumber
  *Pipes
    ..
  *Tools
    ..
  PVC
    ..
{
    ... // other fields of product
    categories: [100, 101, 102, ...]
}
  • 列出所有类别
  • 查找某个类别的所有子类别
  • 查找特定类别中的所有产品
你会发现用你的数据结构做这些事情很困难

我在目前的项目中也遇到了同样的情况。以下是我为您做的参考。
首先,类别应该在一个单独的集合中不要将类别相互嵌套,因为这会使查找所有子类别的过程复杂化。查找所有子类别的传统方法是维护
idPath
属性。例如,您的类别分为3个级别:

{
    _id: 100,
    name: "level1 category"
    parentId: 0,  // means it's the top category
    idPath: "0-100"
}
{
    _id: 101,
    name: "level2 category"
    parentId: 100,
    idPath: "0-100-101"
}
{
    _id: 102,
    name: "level3 category"
    parentId: 101,
    idPath: "0-100-101-102"
}
注意:对于idPath,不再需要parentId。让您更容易理解结构。
一旦需要查找类别100的所有子类别,只需执行以下查询:

db.collection("category").find({_id: /^0-100-/}, function(err, doc) {
    // whatever you want to do
})
由于类别存储在单独的集合中,在您的产品中,您需要通过_id引用它们,就像我们使用RDBMS一样。例如:

-Electrical
  *Wires
    p1
    p2
    ..
  *Tools
    p5
    pn
    ..
  *Sockets
    p11
    p23
    ..
-Plumber
  *Pipes
    ..
  *Tools
    ..
  PVC
    ..
{
    ... // other fields of product
    categories: [100, 101, 102, ...]
}
现在,如果要查找某个类别中的所有产品:

db.collection("category").find({_id: new RegExp("/^" + idPath + "-/"}, function(err, categories) {
    var cateIds = _.pluck(categories, "_id"); // I'm using underscore to pluck category ids
    db.collection("product").find({categories: { $in: cateIds }}, function(err, products) {
        // products are here
    }
})
幸运的是,类别集合通常非常小,里面只有数百条(或数千条)记录。而且变化不大。因此,您可以始终在内存中存储类别的实时副本,并且可以将其构造为嵌套对象,如:

[{
    id: 100,
    name: "level 1 category",
    ... // other fields
    subcategories: [{
        id: 101,
        ... // other fields
        subcategories: [...]
    }, {
        id: 103,
        ... // other fields
        subcategories: [...]
    },
    ...]
}, {
    // another top1 category
}, ...]
您可能希望每隔几个小时刷新一次此副本,因此:

setTimeout(3600000, function() {
    // refresh your memory copy of categories.
});
这就是我现在想到的。希望能有帮助

编辑:

  • 为每个用户提供int-ID,非常有用。您可能有一个idSeed集合:

    {
        _id: ...,
        seedValue: 1,
        forCollection: "user"
    }
    
    当您想要获得唯一ID时:

    db.collection("idSeed").findAndModify({forCollection: "user"}, {}, {$inc: {seedValue: 1}}, {}, function(err, doc) {
        var newId = doc.seedValue;
    });
    
    findAndModify是mongodb提供的原子运算符。它将保证线程安全。查找和修改实际上发生在一个“事务”中

  • 第二个问题已经在我的答案里了
  • 属性的查询子集描述为。nodejsapi几乎相同。阅读
    投影
    参数的文档
  • mongodb操作符的函数也支持更新子集

您需要什么数据库查询?Mongodb是用于读取数据的快速数据库吗?如果你使用索引,请检查我的编辑,@NikolayLukyanchukThanks!我真的在读它,并遵循它。你能检查我最后的编辑吗?我提到了我将要做的CRUD,以及每个寄存器的代码生成。我编辑了我的答案。第一个问题有点棘手,所以我演示了如何做。以下3个问题只是mongodb的常规操作,所以我只留下文档供您阅读。谢谢!为什么,在函数中传递
{$inc:{seedValue:1}}
作为参数?据我所知,我将首先创建一个具有种子值(可能全部为1)的虚拟集合。然后在插入之前,我将获得下一个id(已经增加了)?如果您是这样要求的话,操作符$inc将seedValue增加1。并且在回调中返回更新前的值。因此,每次调用此代码时,它都会给您一个唯一的int-ID。谢谢!还有一个问题:我总是可以通过ajax接收整个文档,包括
\u id
,但是当再次查询每个文档时,我可以将
id
\u id
关联,并按最后一个进行查询,对吗?:)我是Mongo的新手,我喜欢它,现在就使用它,因为爱JS Obecjts/JSON和SQL会吃掉一堆RAM。。。