如何在同一模型的子文档上使用 Mongoose 填充?

问题描述 投票:0回答:1

这是我的产品型号。

const featureHeaderSchema = new Schema({
    header: {
        type: String,
        required: true,
    },
});
const featureSchema = new Schema({
    title: {
        type: String,
        required: true,
    },
    parentHeader: { type: Schema.Types.ObjectId, ref: "product.featureHeaders" }, // not sure if this is correct
    parentFeature: { type: Schema.Types.ObjectId, ref: "product.features" },  // not sure if this is correct
});
const productSchema = new Schema(
    {
        title: {
            type: String,
            required: true,
        },
        thumbnail: String,
        description: String,
        manufacture: { type: Schema.Types.ObjectId, ref: "user" },
        featureHeaders: {
            type: [featureHeaderSchema],
        },
        features: {
            type: [featureSchema],
        },
    },
    { timestamps: true }
);
const productModel = mongoose.model("product", productSchema);

我想通过 id 查找产品并通过 populate 获取parentHeader 的标题和parentFeature 的标题。

我尝试通过产品 ID 获取产品信息并填充到parentHeader 和parentFeature 上,这样我就可以在输出中包含它们的标题。

我尝试了这个查询:

const output = await productModel
    .findById(newProduct._id)
    .populate("features.parentFeature")
    .exec();

但我收到此错误:MissingSchemaError:尚未为模型“product.features”注册架构。

javascript database mongodb mongoose nosql
1个回答
0
投票

首先,你想要做的事情是不可能用

populate
实现的。这是因为模式声明中的
ref
属性用于引用模型,而不是路径。它用于告诉 mongoose 您要使用哪个模型来执行
$lookup
,并且 mongoose 期望该模型与数据库中的集合相对应。

其次,您在

productSchema
中为
featureHeaders
features
数组使用子文档,因此
populate
无论如何都不会为您工作。

幸运的是,您可以解决此问题并让

populate
为您工作。尽管您的命名约定和用例有点令人困惑,但希望这将有助于解释它是如何完成的:

  1. FeatureHeader
    Feature
    需要有自己的集合,而不是子文档,因此您需要为它们创建模型。
import mongoose from "mongoose";
const featureHeaderSchema = new mongoose.Schema({
    header: {
        type: String,
        required: true,
    }
});
// You need create the FeatureHeader model
const FeatureHeader = mongoose.model("FeatureHeader", featureHeaderSchema);

const featureSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true,
    },
    parentHeader: { 
       type: mongoose.Schema.Types.ObjectId, 
       ref: "FeatureHeader" //< Reference the FeatureHeader model
    }, 
    parentFeature: { 
       type: mongoose.Schema.Types.ObjectId, 
       ref: "Feature" //< You can reference the same model (i.e self)
    }
});
// You need create the Feature model
const Feature = mongoose.model("Feature", featureSchema);

const productSchema = new mongoose.Schema({
   title: {
      type: String,
      required: true,
   },
   thumbnail: String,
   description: String,
   manufacture: { 
      type: mongoose.Schema.Types.ObjectId, 
      ref: "User" //< Capitalise the model name
   },
   featureHeaders: [{
      type: mongoose.Schema.Types.ObjectId,
      ref: "FeatureHeader", //< Reference the FeatureHeader model
   }],
   features: [{
      type: mongoose.Schema.Types.ObjectId,
      ref: "Feature", //< Reference the Feature model
   }],
},
{ timestamps: true });
// You need create the Feature model
const Product = mongoose.model("Product", productSchema);
  1. FeatureHeader
    Feature
    需要单独保存在自己的集合中,以便参考。
const newFeatureOne = await Feature.create({
   title: 'Marvel',
});

const newFeatureHeader = await FeatureHeader.create({
   header: 'Superhero'
});

const newFeatureTwo = await Feature.create({
   title: 'Repulsor Beams',
   parentHeader: newFeatureHeader._id,
   parentFeature: newFeatureOne._id
});

const newProduct = await Product.create({
   title: 'Repulsor Beams',
   //...
   //... 
   featureHeaders: [newFeatureHeader._id],
   features: [newFeatureTwo._id],
});
  1. 现在您可以调用
    populate
    ObjectId
    替换为相应的文档:
const id = req.body.id; //< Could be req.params.id or however you get the id

const product = await Product.findById(id)
   .populate("featureHeaders")
   .populate("features");

注意:根据您的设计以及模型的范围,您可能需要指定

path
和/或
model
选项对象的
populate
属性,如下所示:

const id = req.body.id; //< Could be req.params.id or however you get the id

const product = await Product.findById(id)
   .populate({path: "featureHeaders", model: "FeatureHeader"})
   .populate({path: "features", model: "Feature"});
© www.soinside.com 2019 - 2024. All rights reserved.