MongoDB - 插入两个集合,一个集合引用另一个集合作为子文档

时间:2015-11-23 05:32:08

标签: javascript mongodb meteor nosql

来自关系数据库背景的Meteor和MongoDB新手。这个问题实际上反映了我在MongoDB中如何处理关系的难题。

示例:我想将配方插入到配方集合中,在这种情况下,配方是由多个成分组成的逗号分隔字符串。但是,我想要同时将这些成分加入到一系列成分中。而且我想让配方参考配料系列中的成分,这样,如果我第一次得到一种成分的拼写错误,我可以在以后的成分集中更新它并且使用所有配方使用该成分也更新了。

似乎这样做的方法是将食谱集合作为子文档包含在食谱集合中。

但是,我不确定如何实际实现它。使用Meteor的JS中的示例代码如下:

Recipes = new Mongo.Collection("recipes");
Ingredients = new Mongo.Collection("ingredients");

Template.body.events({
    "submit .new-recipe": function(event) {
        // Prevent default browser form submit
        event.preventDefault();

        // Get value from form element
        var text = event.target.text.value;
        var splitText = text.split(",");
        var nInputs = splitText.length;
        var recipe = [];
        for (var i = 0; i < nInputs; i++) {
            // Insert an ingredient into the ingredients collection
            Ingredients.insert({
                itemName: splitText[i].trim(),
                createdAt: new Date() 
            });
            recipe.push(splitText[i]);
        }
        // Insert the list of ingredients as a recipe into the recipes collection
        Recipes.insert({
            recipe: recipe,
            createdAt: new Date()
        });
        // Clear form
        event.target.text.value = "";
    }
});

显然,上述方法无法正常完成工作。它切断了配料和配方之间的关系。但我怎样才能保持这种关系呢?在插入配料时,我是否将配料的Ids放入食谱系列中?在插入配料时,是否将整个配料文件作为配方文件的一部分插入配方集合中?

1 个答案:

答案 0 :(得分:2)

听起来你需要两个集合之间的简单关系模型。这通常通过将一个集合的_id存储为另一个集合中的值来实现。在您的情况下,我建议将配料ID作为数组存储在配方中。我看到你最初尝试的一些问题:

  1. 在插入之前不检查成分的存在。所以两个食谱使用&#34;糖&#34;会插入两份糖文件 - 我认为这不是你的意图。

  2. 插页发生在客户端,但除非您发布整个成分集,否则客户不能成为实际存在成分的权威(以下是 1 )。

  3. 进行插入时,您正在使用客户端的时间戳。如果他们的时钟错了怎么办?实际上a package处理了这个问题,但我们可以使用方法解决上述所有问题。

  4. 我建议在客户端上拆分文本输入,然后发出Meteor.call('recipes.insert', ingredientNames),其中方法实现如下所示:

    Meteor.methods({
      'recipes.insert': function(ingredientNames) {
        // Make sure the input is an array of strings.
        check(ingredientNames, [String]);
    
        // Use the same createdAt for all inserted documents.
        var createdAt = new Date;
    
        // Build an array of ingredient ids based on the input names.
        var ingredientIds = _.map(ingredientNames, function(ingredientName) {
          // Trim the input - consider toLowerCase also?
          var name = ingredientName.trim();
    
          // Check if an ingredient with this name already exists.
          var ingredient = Ingrediends.findOne({itemName: name});
          if (ingredient) {
            // Yes - use its id.
            return ingredient._id;
          } else {
            // Insert a new document and return its id.
            return Ingrediends.insert({
              itemName: name,
              createdAt: createdAt
            });
          }
        });
    
        // Insert a new recipe using the ingredient ids to join the
        // two collections.
        return Recipes.insert({
          ingredientIds: ingredientIds,
          createdAt: createdAt
        });
      }
    });
    

    推荐阅读:

相关问题