2015-11-23 46 views
0

来自关系数据库背景的Meteor和MongoDB的新手。这个问题实际上反映了我在MongoDB中处理关系的困惑。MongoDB - 插入两个集合,一个集合引用另一个作为子文档

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

看来,这样做的方法是将成分集合作为子文档包含在食谱集合中。

但是,我不知道我该如何实际执行该操作。使用流星在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 = ""; 
    } 
}); 

显然,上述不正确地做这项工作。它切断了配料和配方之间的关系。但我如何维持这种关系呢?插入配料时,我是否会将配料中的各种配料放入食谱集合中?在插入配料时,我是否将整个配料文档作为配方文档的一部分插入配方集合中?

回答

2

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

  1. 在插入之前未检查配料的存在。所以两个使用“糖”的食谱会插入两个糖文件 - 我认为这不是你的意图。

  2. 插入发生在客户端,但除非您要发布您的整个配料集合,否则客户不能成为实际存在配料的权威(从开始)。

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


我建议拆分客户端上的文本输入,然后发出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 
    }); 
    } 
}); 

推荐阅读:

+0

非常感谢!除了'check(ingredientNames,[String]);'行之外,一切都可以工作。错误消息说“检查”是一个未知的功能。我错过了什么?它来自一些JS库吗? – MichM

+0

那很奇怪。 [检查](HTTP://docs.meteor。com /#/ full/check)是一个默认包含的软件包。你是否正在运行一个真正旧版本的流星? –

+0

感谢您的线索!通过“流星加检查”解决 – MichM

相关问题