You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mongoose中实现鸡尾酒API的食材用量字段设计?

解决方案:在Mongoose Schema中添加食材用量

Great question! Adding ingredient quantities is essential for any recipe API, and there are clean, maintainable ways to implement this with your existing schemas. Let’s walk through the best approaches and optimizations.

核心方案:修改Cocktail Schema的Ingredients字段为嵌套对象数组

Instead of storing just ObjectId references to ingredients directly, you’ll want to create a nested object that combines the ingredient reference with its quantity and unit. This keeps your data structured and makes queries/population straightforward.

Here’s how to update your Cocktail Schema:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const cocktailSchema = new Schema({ 
  name: { type: String, required: true }, 
  recipe: { type: String, required: true }, 
  // 替换原ingredients字段为嵌套对象数组
  ingredients: [{
    ingredient: { 
      type: mongoose.Schema.Types.ObjectId, 
      ref: 'Ingredient', 
      required: true 
    },
    quantity: { type: Number, required: true }, // 数值用量(比如2、1)
    unit: { type: String, required: true } // 单位(比如"cl"、"汤匙"、"盎司")
  }], 
  creator: { type: mongoose.Schema.Types.ObjectId, ref:'User' }, 
  createdDate: { type: Date, default: Date.now } 
});

module.exports = mongoose.model('Cocktail', cocktailSchema);

为什么这个方案更好?

  • Separation of concerns: You keep the ingredient’s core data (name, alcoholic status) in the Ingredient schema, while storing recipe-specific details (quantity, unit) directly in the cocktail.
  • Easy population: When querying cocktails, you can populate the ingredient reference to get full ingredient details alongside the quantity:
    // 示例:获取带完整食材和用量的鸡尾酒
    Cocktail.findById('your-cocktail-id')
      .populate('ingredients.ingredient') // 嵌套populate
      .exec((err, cocktail) => {
        if (err) throw err;
        // 输出示例:{ name: "Martini", ingredients: [{ ingredient: { name: "Gin", alcoholic: true }, quantity: 6, unit: "cl" }, ...] }
        console.log(cocktail);
      });
    
  • Maintainability: If you ever need to update how quantities are stored (e.g., add support for metric/imperial conversions), you only need to modify this nested object instead of restructuring your entire schema.

灵活扩展:支持描述性用量

If you need to handle non-numeric quantities (like "a pinch" or "to taste"), you can adjust the schema to support both numeric and descriptive values:

ingredients: [{
  ingredient: { 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'Ingredient', 
    required: true 
  },
  // 数值型用量(可选)
  quantityValue: { type: Number },
  unit: { type: String },
  // 描述性用量(可选,比如"少许"、"适量")
  quantityDescription: { type: String },
  // 可选:添加验证确保至少提供一种用量
  validate: {
    validator: function(v) {
      return (this.quantityValue && this.unit) || this.quantityDescription;
    },
    message: props => 'Either quantityValue + unit or quantityDescription must be provided!'
  }
}]

优化建议

  • Add enums for units: To keep units consistent (avoid "cl" vs "centiliter"), define an enum of allowed units:
    unit: { 
      type: String, 
      required: true,
      enum: ['cl', 'ml', '汤匙', '茶匙', '盎司', '杯'] // 根据你的需求扩展
    }
    
  • Index for faster queries: Add an index on ingredients.ingredient to speed up queries that filter by specific ingredients:
    cocktailSchema.index({ 'ingredients.ingredient': 1 });
    
  • Avoid mixing data types: Stick to either numeric quantities + units or descriptive strings—don’t try to store both in a single field (like you initially considered with a string). This will make filtering, sorting, and data manipulation much easier down the line.

内容的提问来源于stack exchange,提问作者Jef Vandooren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 10:52:40