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

MongoDB - insert into two collections, one collection referencing the other as subdocument

本文关键字:集合 另一个 引用 文档 一个 插入 两个 MongoDB-      更新时间:2023-09-26

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 = "";
    }
});

显然,以上内容不能正确地完成任务。它切断了配料和食谱之间的关系。但是我该如何维持这种关系呢?在插入配料时,我是否将配料的ID放入食谱集合?在插入配料时,我是否将整个配料文档作为配方文档的一部分插入到配方集合中?

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

  1. 在插入之前没有检查成分的存在。所以两个使用"糖"的食谱会插入两个糖文档——我想这不是你的本意。

  2. 插入是在客户端上进行的,但除非您发布整个成分集合,否则客户端不能是实际存在哪些成分的权威(从1开始)。

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


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

推荐阅读:

  • 这个关于流星中关系模型的问题