Database 如何使用MongoDB为配方/配料正确设计数据模型

Database 如何使用MongoDB为配方/配料正确设计数据模型,database,mongodb,mongodb-query,many-to-many,erd,Database,Mongodb,Mongodb Query,Many To Many,Erd,最近,我使用Hackalode设计了一个数据库模型或ERD。 因此,我目前面临的问题是,基于我目前的设计,我无法按照我的要求正确地查询它。我用MYSQL研究了ERD,我知道Mongo的工作原理不一样 这个想法很简单,我想要一个配方,有一系列的成分,成分是从单独的收集。 配方还包括成分的测量,即(1汤匙糖) 还可以从配料列表中查询并找到包含配料的配方 我希望这些集合具有多对多关系,并且配方可以使用数据库中已有的成分 我只是不知道如何查询数据 通过使用$elemMatch和populate,我尝试

最近,我使用Hackalode设计了一个数据库模型或ERD。 因此,我目前面临的问题是,基于我目前的设计,我无法按照我的要求正确地查询它。我用MYSQL研究了ERD,我知道Mongo的工作原理不一样

这个想法很简单,我想要一个配方,有一系列的成分,成分是从单独的收集。 配方还包括成分的测量,即(1汤匙糖)

还可以从配料列表中查询并找到包含配料的配方

我希望这些集合具有多对多关系,并且配方可以使用数据库中已有的成分

我只是不知道如何查询数据

通过使用$elemMatch和populate,我尝试了很多方法,结果得到的是空数组列表

我期待两种类型的查询,我可以查询的成分名称或配方

我的预期结果是这样的

[{
   id: ...,
   name: ....,
   description: ...,
   macros: [...],
   ingredients: [
   {
       id,
       amount: ....,
       unit: ....
       ingredient: {
           id: ....,
           name: ....
       }
   }
}, { ... }]
而不是

[]

哦,你的设计完全错了。您过度规范化了数据。我会做一些更简单的事情并使用嵌入。其背后的理由是,首先定义用例,然后对数据建模,以最有效的方式回答用例中出现的问题

假定用例
  • 作为一个用户,我想要一个所有食谱的列表
  • 作为一个用户,我想要一份所有配方的列表
  • 作为一名设计师,我希望能够展示所有成分的列表
  • 作为一个用户,我希望能够链接到配方的复合成分,如果它出现在网站上
  • 当然,这只是一个小摘录,但对于这个例子来说已经足够了

    如何回答问题 好的,第一个非常简单:

    db.recipes.find()[.limit()[.skip()]]
    
    db.recipes.find({$text:{$search:"ingredient name"}})
    
    现在,我们怎样才能找到配料呢?简单回答:对成分名称(可能还有其他一些字段)进行文本索引。然后,查询同样简单:

    db.recipes.find()[.limit()[.skip()]]
    
    db.recipes.find({$text:{$search:"ingredient name"}})
    
    “嘿,等一下!我怎样才能得到所有成分的列表?”让我们假设我们想要一个简单的成分列表,上面有一个关于它们实际使用频率的数字:

    db.recipes.aggregate([
      // We want all ingredients as single values
      {$unwind:"$Ingredients"},
      // We want the response to be "Ingredient"
      {$project:{_id:0,"Ingredient":"$Ingredients.Name"}
      // We count the occurrence of each ingredient
      // in the recipes
      {$group:{_id:"$Ingredient",count:{$sum:1}}}
    ])
    
    这实际上就足够了,除非你有一个包含无数配方的数据库。在这种情况下,你可能需要深入研究而不是聚合。提示:你应该在配方中添加一个时间戳,以便能够使用增量映射/减少

    如果你有几十万到几百万个食谱,你也可以添加一个阶段来预聚合你的数据

    关于测量 嗯,定义尺寸是没有意义的。有茶匙、汤匙、公制和英制尺寸,有“打”之类的分组,也有“丁香”之类的规格。你真的不想相互转换,甚至不想设置为有限的尺寸。一个大蒜丁香有多少盎司?;)

    一句话:让它成为一个自由的文本字段,可能有一些自动完成的建议

    修正数据模型 配方 以及文本索引的示例:

    db.recipes.createIndex({Name:"text","Ingredients.Name":"text"})
    
    背后的理论 配方是您的基本数据结构,因为您的应用程序应该存储和提供它们,可能基于某些标准。成分和测量(在合理的范围内)可以很容易地从配方中得出。那么,为什么要费心独立储存成分和测量数据呢。它只会使您的数据模型变得不必要的复杂,而不会提供任何优势


    嗯,你的设计完全错了。您过度规范化了数据。我会做一些更简单的事情并使用嵌入。其背后的理由是,首先定义用例,然后对数据建模,以最有效的方式回答用例中出现的问题

    假定用例
  • 作为一个用户,我想要一个所有食谱的列表
  • 作为一个用户,我想要一份所有配方的列表
  • 作为一名设计师,我希望能够展示所有成分的列表
  • 作为一个用户,我希望能够链接到配方的复合成分,如果它出现在网站上
  • 当然,这只是一个小摘录,但对于这个例子来说已经足够了

    如何回答问题 好的,第一个非常简单:

    db.recipes.find()[.limit()[.skip()]]
    
    db.recipes.find({$text:{$search:"ingredient name"}})
    
    现在,我们怎样才能找到配料呢?简单回答:对成分名称(可能还有其他一些字段)进行文本索引。然后,查询同样简单:

    db.recipes.find()[.limit()[.skip()]]
    
    db.recipes.find({$text:{$search:"ingredient name"}})
    
    “嘿,等一下!我怎样才能得到所有成分的列表?”让我们假设我们想要一个简单的成分列表,上面有一个关于它们实际使用频率的数字:

    db.recipes.aggregate([
      // We want all ingredients as single values
      {$unwind:"$Ingredients"},
      // We want the response to be "Ingredient"
      {$project:{_id:0,"Ingredient":"$Ingredients.Name"}
      // We count the occurrence of each ingredient
      // in the recipes
      {$group:{_id:"$Ingredient",count:{$sum:1}}}
    ])
    
    这实际上就足够了,除非你有一个包含无数配方的数据库。在这种情况下,你可能需要深入研究而不是聚合。提示:你应该在配方中添加一个时间戳,以便能够使用增量映射/减少

    如果你有几十万到几百万个食谱,你也可以添加一个阶段来预聚合你的数据

    关于测量 嗯,定义尺寸是没有意义的。有茶匙、汤匙、公制和英制尺寸,有“打”之类的分组,也有“丁香”之类的规格。你真的不想相互转换,甚至不想设置为有限的尺寸。一个大蒜丁香有多少盎司?;)

    一句话:让它成为一个自由的文本字段,可能有一些自动完成的建议

    修正数据模型 配方 以及文本索引的示例:

    db.recipes.createIndex({Name:"text","Ingredients.Name":"text"})
    
    背后的理论 配方是您的基本数据结构,因为您的应用程序应该存储和提供它们,可能基于某些标准。成分和测量(在合理的范围内)可以很容易地从配方中得出。那么,为什么要费心独立储存成分和测量数据呢。它只会使您的数据模型变得毫无意义