web-dev-qa-db-fra.com

Enregistrement d'objets imbriqués dans la mangouste

Venant d’un contexte PHP/MySQL, je lutte contre les meilleures pratiques en termes de structuration et de sauvegarde de mes données.

J'essaie de créer une petite application où je peux ajouter des recettes avec plusieurs ingrédients. J'ai un tas d'ingrédients pré-remplis comme données de base, dont le schéma ressemble à:

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);

Une recette ressemble actuellement à ceci:

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);

Enfin, j'ai un RecipeIngredientSchema. Maintenant, c’est là que mes antécédents MySQL pourraient s’insérer; La raison pour laquelle je l'ai fait de cette façon est que je veux la relation un à plusieurs entre Recipes et Ingredients, mais je veux aussi pouvoir spécifier une unité:

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);

Ma question est en deux parties:

  • Est-ce que je m'y intéresse de manière sensée en termes de modélisation de données ou suis-je loin?
  • À quoi ressemblerait le processus de sauvegarde d'une recette avec plusieurs ingrédients? 

Je pense actuellement à ce qui suit:

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

Je pense que c'est compliqué et généralement faux , alors j'apprécierais quelques conseils!

14
James

L'avantage des bases de données NoSQL (ou des magasins de documents en général) est qu'il n'est pas nécessaire de fractionner vos données en plusieurs tables/collections. Vous pouvez stocker toutes les données liées dans une seule entité afin que vos opérations de lecture se déroulent en une fois. 

Il n’existe pas d’approche "correcte" pour ce faire, mais si vous utilisez NoSQL, je considérerais de sauvegarder la recette complète (recette, ingrédients et instructions) en tant que document unique plutôt que de scinder les données en 3 ou 4 tableaux. modèle relationnel.

Par exemple, je voudrais enregistrer une seule recette comme suit:

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'} 
    ]
}

Maintenant, ce n'est pas la poussière de lutin. Il arrivera parfois que le fractionnement des données en plusieurs tables/collections et l'utilisation d'un langage de requête relationnel (comme SQL) soient bénéfiques pour les données de requête. Par exemple, si vous souhaitez interroger toutes les recettes utilisant des «tomates», une base de données relationnelle avec une table de jointure pour les relations recette/ingrédients simplifierait beaucoup cette approche par rapport à l'approche NoSQL. 

C'est une décision que vous devrez prendre à un moment donné: préférez-vous un NoSQL ou un RBMS pour votre application?

9
Hector Correa

Si vous souhaitez enregistrer des objets imbriqués dans la base de données, vous avez deux options: schéma intégré ou avec réf. Si vous les enregistrez avec les références, le schéma imbriqué est enregistré dans une collection séparée.

Commencez à regarder cet exemple mongo-many-to-many et celui-ci section: saving-refs

1
maxi-code