【问题标题】:Saving nested objects in mongoose在猫鼬中保存嵌套对象
【发布时间】:2014-02-10 04:24:28
【问题描述】:

来自 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);
              });
            }
          });
        };
      }
    }
  });
}

我觉得这很复杂,而且通常,所以希望得到一些指导!

【问题讨论】:

    标签: node.js mongodb express mongoose


    【解决方案1】:

    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)将有利于查询数据。例如,如果您想查询所有使用“西红柿”的食谱,并拥有一个带有用于食谱/配料关系的连接表的关系数据库,这将比 NoSQL 方法简单得多。

    这是您需要在某一时刻做出的决定:对于您的应用程序,您是使用 NoSQL 还是使用 RBMS 更好?

    【讨论】:

    • 同意。工程师会根据问题来选择他们的技术,而不是因为特定的技术是“趋势”或“更容易”。如果数据是关系数据,那么您不应该尝试在非关系数据存储上强制使用关系范式。
    • 我正在考虑这种方法,但想知道如何对数据进行规范化,以便成分不会重复,但也可以有不同的单位。我的目标是简单地掌握 node/mongodb,而不是创建一个功能齐全的产品,所以我只是在探索我的选择。谢谢你的回答,我看看效果如何!
    • 我不同意你关于“找到所有使用'西红柿'的食谱”的观点。使用您的示例,您只需执行recipes.find({'ingredients.name': 'tomatoes'})。 Mongo 的读取速度非常快,因此这应该比 sql 中的 JOIN 快得多。
    • 因此,关键是我们并没有真正规范 MongoDB 中的数据?
    【解决方案2】:

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

    开始看看这个例子mongo-many-to-many和这个section: saving-refs

    【讨论】:

      【解决方案3】:

      您可以使用“最小化”选项来自动保存子文档,同时保存父文档。

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

      【讨论】:

        猜你喜欢
        • 2014-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-12
        • 2014-07-13
        • 1970-01-01
        • 1970-01-01
        • 2019-07-14
        相关资源
        最近更新 更多