【问题标题】:Populate an object referenced by another object填充另一个对象引用的对象
【发布时间】:2018-03-19 02:13:32
【问题描述】:

我有一个产品列表,每个产品都有自己的选项。例如:

  • 蓝色连衣裙(S - L)
  • 红色连衣裙(XS - S - M)

蓝色连衣裙红色连衣裙是产品,SLXS em>、SM 是选项。选项模型有对产品模型的引用,我想检索所有产品然后列出他们自己的选项。

我只想通过一个查询来实现它,我的问题是我从没有链接到其选项的产品开始。因此,我开始查找所有产品,并使用带有 foreach 循环的嵌套 then 获得所有选项。然后我尝试将选项分配给产品对象(在我的情况下,forEach 中的 productElem),但是当我将其检索到范围之外时,它当然是空的。如何从产品查询开始填充选项?

产品架构:

var schema = new Schema({
  imagePath: {type: String},
  title: {type: String, required: true},
  description: {type: String, required: true}
});

选项架构:

var productOptionSchema = new Schema({
  type: {type: String, enum: ['grams'], default: 'grams', required: true},
  value: {type: String, required: true},
  price: {type: Number, required:true},
  product: {type: Schema.Types.ObjectId, ref: 'User', required:true}
});

这里我在找到产品后尝试获取选项

router.get('/shop/products/list', isLoggedIn, function (req, res, next) {
  Product.find()
    .then(function (products) {
      products.forEach(function(productElem) {
        ProductOption.find({product: productElem._id})
          .then(function (options) {
            productElem['options'] = [];
            options.forEach(function(optionElem) {
              productElem['options'].push(optionElem);
            });
          });
      });
      res.render('shop/listProduct', {user:req.user, csrfToken: req.csrfToken(), messages:messages, partialCustom: 
      });
    })
    .catch(function (err) {
      console.log('Error ' + err.code + ': ', err.message);
      res.status(500).send('Failed to get the Product List from the DB: ' + err);
    });
});

【问题讨论】:

  • 你的问题不是很清楚。请编辑问题以使其更易于理解。

标签: node.js mongoose mongoose-populate


【解决方案1】:

您的代码存在一些缺陷。 forEach 循环试图找到基于product ID 的所有选项,这在这里看起来是一种显而易见的方法,但这里的问题是find() 方法的异步性质。

由于find() 的异步特性,forEach 循环在不等待单个find() 的结果的情况下完成,因此options 尚未填充。在循环之后,它只是渲染“shops/listProduct”,这显然没有产品选项。

您可以做的是将所有find() 推送到promises 数组中,等待所有使用Promise.all() 的承诺返回。在所有的promise都成功完成后做res.render('shops/listProduct',{...})

替代方法:

我有一个更简单的方法来使用aggregation 实现您想要的。

试试这个:

ProductOption.aggregate([{
    $group : {
        _id : product,
        options : {$push : "$$ROOT"}
    }
},{
    $lookup : {
        from : "products",
        localField : "_id",
        foreignField : "_id",
        as : "product"
    }
},{
    $unwind : {
        path : "$product",
        preserveNullAndEmptyArrays : true
    }
},{
    $project : {
        _id : "$product._id"
        imagePath : "$product.imagePath",
        title : "$product.title",
        description : "$product.description",
        options : "$options"
    }
}],function(err,result){
    //result will have all the products with their options
});

$group 将根据 product(即产品 ID)对选项进行分组,$lookup 将填充产品对象,$project 将以您想要的方式返回结果。

阅读 mongodb Aggregation$group$lookup$project 以更好地理解它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-18
    • 2022-11-26
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    相关资源
    最近更新 更多