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

时间:2019-01-02 11:54:35

标签: database mongodb mongodb-query many-to-many erd

最近,我已经使用Hackalode设计了数据库模型或ERD。 因此,我目前面临的问题是基于当前的设计,我无法正确查询它。我用MYSQL学习了ERD,但确实知道Mongo不能正常工作

这个想法很简单,我想要一个食谱,里面有一系列的食材,而这些食材来自不同的馆藏。 配方还包括成分的测量。 (1汤匙糖)

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

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

Current design of data model

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

我使用$ elemMatch进行了很多尝试并填充,结果我得到的只是空数组列表。

我希望有两种查询方式,我可以按配料名称或配方进行查询

我的期望结果将是这样

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

但是没有得到

[]

1 个答案:

答案 0 :(得分:1)

天哪,您的设计完全错误。您过度规范化了您的数据。我会做一些更简单的事情,并使用嵌入。其背后的原因是,先定义用例,然后再建模数据,以最有效的方式回答用例引起的问题。

假定的用例

  1. 作为用户,我想要所有食谱的列表。
  2. 作为用户,我想要按配料列出所有食谱。
  3. 作为设计师,我希望能够显示所有成分的列表。
  4. 作为用户,我希望能够链接到复合配料的配方,只要该配方存在于网站上。

当然,这只是一小部分摘录,但对于此示例来说就足够了。

如何回答问题

好吧,第一个非常简单:

db.recipes.find()[.limit()[.skip()]]

现在,我们如何才能按成分查找?简单的答案:对成分名称(可能还有其他字段as you can only have one text index per collection)进行文本索引。然后,查询同样简单:

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}}}
])

这实际上就足够了,除非您有数以百万计的食谱数据库。在这种情况下,您可能希望深入了解incremental map/reduce而不是汇总。 提示:您应该在配方上添加时间戳,以便能够使用增量映射/缩小。

如果您有几百个K到几百万个食谱,则还可以添加一个$out阶段来预汇总数据。

在测量中

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

底线:将其设置为自由文本字段,其中可能包含一些自动完成建议。

修订后的数据模型

食谱

{
  _id: new ObjectId(),
  Name: "Surf & Turf Kebap",
  Ingredients: [
    {
      Name: "Flunk Steak",
      Measurement: "200 g"
    },
    { 
      Name: "Prawns",
      Measurement: "300g",
      Note: "Fresh ones!"
    },
    {
      Name: "Garlic Oil",
      Measurement: "1 Tablespoon",
      Link: "/recipes/5c2cc4acd98df737db7c5401"
    }
  ]
}

还有文本索引的示例:

db.recipes.createIndex({Name:"text","Ingredients.Name":"text"})

背后的理论

配方是您的基本数据结构,因为您的应用程序可能会基于某些条件来存储和提供它们。成分和度量(在有意义的范围内)可以轻松地从食谱中得出。那么,为什么还要麻烦地独立存储成分和测量值。它只会使您的数据模型不必要地复杂,而不会提供任何优势。

hth