Database 如何使用MongoDB为配方/配料正确设计数据模型
最近,我使用Hackalode设计了一个数据库模型或ERD。 因此,我目前面临的问题是,基于我目前的设计,我无法按照我的要求正确地查询它。我用MYSQL研究了ERD,我知道Mongo的工作原理不一样 这个想法很简单,我想要一个配方,有一系列的成分,成分是从单独的收集。 配方还包括成分的测量,即(1汤匙糖) 还可以从配料列表中查询并找到包含配料的配方 我希望这些集合具有多对多关系,并且配方可以使用数据库中已有的成分 我只是不知道如何查询数据 通过使用$elemMatch和populate,我尝试了很多方法,结果得到的是空数组列表 我期待两种类型的查询,我可以查询的成分名称或配方 我的预期结果是这样的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,我尝试
[{
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"})
背后的理论
配方是您的基本数据结构,因为您的应用程序应该存储和提供它们,可能基于某些标准。成分和测量(在合理的范围内)可以很容易地从配方中得出。那么,为什么要费心独立储存成分和测量数据呢。它只会使您的数据模型变得毫无意义