同一模式中的引用字段

时间:2013-09-24 19:54:19

标签: 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 ingredients array?
    }], 
    ingredients: [{
      name: String,
      category: String
    }]  
});

1 个答案:

答案 0 :(得分:3)

简短回答

这是MongoDB的核心设计决策:MongoDB relationships: embed or reference?

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

通过明确定义IngredientSchema,每个成分对象在声明时都会获得自己的ObjectId。存储成分ID(而不是成分对象的副本)的好处是更简洁和一致的存储。缺点是会有越来越复杂的查询。

[{  username: 'bob', 
    ingredients: [  { _id: ObjectId('a298d9ef898afc98ddf'), name: 'Carrot', category: 'Vegetable' } , ...],
    foods:  [ { name: 'Salad', category: 'Lunch', ingredients: [ {$oid: 'a298d9ef898afc98ddf'}, ]}]
}, ...]

如果您想存储对Ingredients的引用,更好的方法可能是将Ingredients存储为自己的第一类集合。当你想按成分或食物成分查找食物时,你仍然会有很多单独的查询,但查询会更简单。

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查询子文档: Reading categories and number of articles in a single query

正如一位受访者所说,“这是关系数据库真正发挥作用的案例之一”