Сохранение вложенных объектов в мангусте

Я новичок в node.js и MongoDb (и базы данных документов в целом), так голый со мной. Исходя из фона 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);
              });
            }
          });
        };
      }
    }
  });
}

Я чувствую, что это запутанно и, как правило, неправильно, поэтому было бы полезно получить какое-то руководство!

Ответы

Ответ 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 для вашего приложения?

Ответ 2

Если вы хотите сохранить вложенные объекты в БД, у вас есть два варианта: встроенная схема или ссылка. Если вы сохраните их, указав их, вложенная схема будет сохранена в отдельной коллекции.

Начните смотреть на этот пример mongo-many-to-many и этот раздел: save-refs