在mongoose中保存嵌套对象

时间:2014-01-20 20:27:36

标签: node.js mongodb express mongoose

来自PHP / MySQL背景,我在构建和保存数据方面遇到了最佳实践。

我正在尝试创建一个小应用程序,我可以添加多种成分的食谱。我有一堆预先填充的成分作为种子数据,其架构如下:

var IngredientSchema = new Schema({
    name: {
        type: String,
        trim: true,
        required: true,
        index: {
            unique: true
        }
    },
    created: {
        type: Date,
        default: Date.now
    }
});

var Ingredient = mongoose.model('Ingredient', IngredientSchema);

目前的配方如下:

var RecipeSchema = new Schema({
    name: {
      type: String,
      trim: true
    },
    ingredients: [
      {
        type: Schema.Types.ObjectId,
        ref: 'RecipeIngredient'
      }
    ],
    created: {
      type: Date,
      default: Date.now
    }
});

var Recipe = mongoose.model('Recipe', RecipeSchema);

最后,我有一个RecipeIngredientSchema。现在,这是我的MySQL背景可能正在蔓延的地方;我这样做的原因是因为我想要食谱和配料之间的一对多关系,但我也希望能够指定一个单位:

var RecipeIngredientSchema = new Schema({
    recipe: {
      type: Schema.Types.ObjectId,
      ref: 'Recipe'
    },
    ingredient: {
      type: Schema.Types.ObjectId,
      ref: 'Ingredient'
    },
    unit: {
      type: Schema.Types.ObjectId,
      ref: 'Unit'
    },
    created: {
      type: Date,
      default: Date.now
    }
});

var RecipeIngredient = mongoose.model('RecipeIngredient', RecipeIngredientSchema);

我的问题分为两部分:

  • 我是否在数据建模方面以明智的方式解决这个问题,或者我离开了?
  • 用多种成分保存配方的过程实际上是什么样的?

我目前正在考虑以下事项:

exports.create = function(req, res) {

  var recipe = new Recipe(req.body);

  recipe.save(function(err, recipe) {
    if (err) {
      return res.jsonp(err);
    } else {

      // Loop ingredients
      if (req.body.ingredients) {
        for(var prop in req.body.ingredients) {
          var recipeIngredient = new RecipeIngredient({
            recipeId: recipe._id,
            ingredientId: mongoose.Types.ObjectId(req.body.ingredients[prop])
          });

          recipeIngredient.save(function(err, recipeIngredient) {
            if (err) {
              return res.jsonp(err);
            } else {
              recipe.recipeIngredients.push(recipeIngredient._id);
              recipe.save(function(err, recipe) {
                return res.jsonp(recipe);
              });
            }
          });
        };
      }
    }
  });
}

我觉得这很复杂,一般错误,所以会很感激一些指导!

3 个答案:

答案 0 :(得分:9)

NoSQL数据库(或一般的文档存储)的优点在于您不必将数据拆分为多个表/集合。您可以将所有相关数据存储到单个实体中,以便一次性完成读取操作。

没有“正确”的方法来做到这一点,但是如果你打算使用NoSQL,我会考虑将整个配方(配方和成分和方向)保存为单个文档,而不是将数据分成3或4个表a-la关系模型。

例如,我会按如下方式保存单个食谱:

recipe = {
    name: 'name of recipe'
    time: '45 minutes'
    ingredients : [
       {qty: 3, unit: 'item', name: 'tomatoes'},
       {qty: 0.5, unit: 'tbs', name: 'salt'},
       {qty: 1, name: 'item', name: 'avocado'} 
    ]
}

现在,这不是小精灵的尘埃。有时将数据拆分成多个表/集合并使用关系查询语言(如SQL)将有利于查询数据。例如,如果您想查询所有使用'tomato'的配方,这些配方使用关系数据库和配方/配料关系的连接表,这将比NoSQL方法简单得多。

这是您需要做出的决定:您是否更适合使用NoSQL或针对您的应用程序使用RBMS?

答案 1 :(得分:1)

如果要在DB中保存嵌套对象,您有两种选择:作为嵌入式架构或使用ref。如果使用ref它们保存它们,则嵌套模式将保存在单独的集合中。

开始查看此示例mongo-many-to-many和此section: saving-refs

答案 2 :(得分:0)

您可以使用“最小化”作为在保存父文档时自动保存子文档的选项。

const UserSchema = new mongoose.Schema({
  name : String,
  email : String,
},{
  minimize : true
});