Mongodb 同一架构中的引用字段
是否可以引用同一架构中的字段?请参见下面的示例。还是我走错了方向Mongodb 同一架构中的引用字段,mongodb,mongoose,Mongodb,Mongoose,是否可以引用同一架构中的字段?请参见下面的示例。还是我走错了方向 var UserSchema = new mongoose.Schema ({ username: String, password: String, email: String, foods: [{ name: String, category: String, ingredients: // how to reference values in the ing
var UserSchema = new mongoose.Schema ({
username: String,
password: String,
email: String,
foods: [{
name: String,
category: String,
ingredients: // how to reference values in the ingredients array?
}],
ingredients: [{
name: String,
category: String
}]
});
简短回答 这是MongoDB的核心设计决策: 存储对对象的引用,而不是像在关系数据库中那样存储对象的独立副本,这在MongoDB中是可能的,而且通常都是这样,当您需要查找对象时,它只会导致越来越复杂的查询 长答案 如果目标只是保持成分模式的定义一致,那么可以定义一个模式并使用两次。成分将作为独立副本储存,例如:
[{ username: 'bob',
ingredients: [ { name: 'Carrot', category: 'Vegetable' } , ...],
foods: [ { name: 'Salad', category: 'Lunch', ingredients: [ { name: 'Carrot', category: 'Vegetable'}, ...]}]
}, ...]
var IngredientSchema = new mongoose.Schema({
name: String,
category: String,
});
var UserSchema = new mongoose.Schema ({
username: String,
password: String,
email: String,
foods: [{
name: String,
category: String,
ingredients: [IngredientSchema] // brackets indicates it's an array,
}],
ingredients: [IngredientSchema]
});
或者,您可以通过objectId引用成分:
var UserSchema = new mongoose.Schema ({
username: String,
password: String,
email: String,
foods: [{
name: String,
category: String,
ingredients: [mongoose.Schema.Types.ObjectId] // IDs reference individual ingredients,
}],
ingredients: [IngredientSchema]
});
通过显式定义IngreditSchema,每个Component对象在声明时都会获得自己的ObjectId。存储成分ID(而不是成分对象的副本)的好处是更简洁和一致的存储。缺点是会有越来越复杂的查询
[{ username: 'bob',
ingredients: [ { _id: ObjectId('a298d9ef898afc98ddf'), name: 'Carrot', category: 'Vegetable' } , ...],
foods: [ { name: 'Salad', category: 'Lunch', ingredients: [ {$oid: 'a298d9ef898afc98ddf'}, ]}]
}, ...]
如果您想存储对配料的引用,更好的方法可能是将配料存储为自己的第一类集合。当您想按配料或按食品配料查找食品时,仍然会有许多单独的查询,但查询会更简单
var UserSchema = new mongoose.Schema ({
username: String,
password: String,
email: String,
foods: [{
name: String,
category: String,
ingredients: [mongoose.Schema.Types.ObjectId] // IDs reference individual ingredients,
}],
ingredients: [mongoose.Schema.Types.ObjectId]
});
如果目标是存储对配料的规范化引用,并根据它们搜索食品,那么引用另一个[SO post][1],“这是关系数据库真正发挥作用的案例之一”
有关按Id查询子文档的信息,请参见本SO帖子:
正如一位受访者指出的,“这是关系数据库真正闪耀的案例之一”这是否意味着如果我想使用引用而不是嵌入,我必须创建两个模式?我最初的想法是将“成分”字段保留在用户模式下,因为每个用户都可以定义自己的成分集。现在有了新的IngreditSchema,我将把所有用户的成分存储在一个模式(集合)下。那不是我真正需要的。难道没有其他方法吗?另外,试着理解为什么您建议引用foods.Components字段和Components字段中的InCreditSchema。你能给我解释一下吗?在我给出的示例中,配料只有一个模式,但配料对象在每种食物中都是以副本而不是引用的形式逐字存储的。但我知道你想通过ID来引用成分,而不是重复。将编辑上面的答案…非常感谢更新的答案,它为我的问题提供了一些线索。我之所以希望参考成分而不是存储副本,是因为我希望用户能够轻松地更新成分(例如,用户意识到成分中存在拼写错误并希望更正)。更新每个成分的多个副本可能太复杂了。除非有一个神奇的MongoDB操作符,我还没有发现,它可以很容易地更新整个文档中出现的字符串:)我有一个类似的情况,出于许多原因喜欢MongoDB。我建议将配料作为一级集合保存,并将_id属性存储在配料数组中。如果以后需要查找含有特定成分的用户或食品,请使用$in查询运算符。