填充另一个对象引用的对象

时间:2017-10-07 11:55:45

标签: node.js mongoose mongoose-populate

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

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

蓝色连衣裙红色连衣裙是产品, S L XS S M 是选项。选项模型引用了产品模型,我想检索所有产品,然后列出自己的选项。

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

产品架构:

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

1 个答案:

答案 0 :(得分:0)

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

由于forEach的异步性质,find()循环已完成,无需等待单个options的结果,因此find()尚未promises人口稠密。在循环之后,它只是渲染&shop; list / listProduct',显然没有产品选项。

您可以做的是将所有Promise.all()推送到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

$lookup会根据$project(即产品ID)package com.kafka.api.models; import java.io.Serializable; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; @JsonRootName("person") public class Person implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private String personalID; private String country; private String occupation; public Person() { } @JsonCreator public Person(@JsonProperty("name") String name,@JsonProperty("personalID") String personalID, @JsonProperty("country") String country,@JsonProperty("occupation") String occupation){ this.name= name; this.personalID = personalID; this.country = country; this.occupation = occupation; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPersonalID() { return personalID; } public void setPersonalID(String personalID) { this.personalID = personalID; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getOccupation() { return occupation; } public void setOccupation(String occupation) { this.occupation = occupation; } @Override public String toString() { return "{" + " " + "Name :" + " " + name + " " + "ID :" + " " + personalID + " " + "Country :" + " " + country + " " + "Occupation :" + " " + occupation + "}"; } } 对选项进行分组,以填充产品对象,string headLine = "Example"; Console.WriteLine(headLine); for (char i = '='; i <= headLine.Length; i += '=') { Console.WriteLine(i); } 会将结果返回给您你要的那个。

了解mongodb Aggregation$group$lookup$project以便更好地了解它。