简短的回答
这是 MongoDB 的核心设计决策: 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]
});
通过显式定义成分模式,每个成分对象在声明时都会获得自己的 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 帖子][1],“这是关系数据库真正闪耀的案例之一”
请参阅此 SO 帖子以按 ID 查询子文档:
在单个查询中阅读类别和文章数量
正如一位受访者所说,“这是关系数据库真正大放异彩的案例之一”