为啥 Virtual Populate 不能在 Node js 和 mongoose 上运行?场景:产品和用户评论

Posted

技术标签:

【中文标题】为啥 Virtual Populate 不能在 Node js 和 mongoose 上运行?场景:产品和用户评论【英文标题】:why Virtual Populate not working on Node js and mongoose? Scenario : Product and Review by user为什么 Virtual Populate 不能在 Node js 和 mongoose 上运行?场景:产品和用户评论 【发布时间】:2021-08-13 11:29:30 【问题描述】:

我有评论和产品模型。如果用户对特定产品(id)进行评论,那么它将存储在评论模型数据库中,但我不喜欢将用户评论存储在产品模型数据库中。所以,我在产品模型中使用了虚拟填充而不是子引用。使用虚拟属性后,如果我们使用产品ID查看详细信息,我们可以看到json格式的用户评论但未保存在数据库中。但问题是我的虚拟属性(在产品模型中)无法正常工作当我在该产品 id 中发送请求时,不以 json 格式显示用户的评论,该产品 id 已经被用户评论(存储在评论模型数据库中)。这里有什么问题?

用户对存储在数据库中的产品 (id) 的评论

使用虚拟属性发送该产品 ID 的请求以查看 json 格式的用户评论(但在 json 中未找到评论)

在产品模型中

const productSchema = new Schema(

    name: 
        type: String,
        required: true,
        trim: true,
    ,

    slug: 
        type: String,
        required: true,
        unique: true,
    ,
    price: 
        type: String,
        required: true,
    ,
    quantity: 
        type: Number,
        required: true,
    ,
    description: 
        type: String,
        required: true,
        trim: true,
    ,
    offer: 
        type: Number,
    ,
    discount: 
        type: Number,
    ,
    productPictures: [
        img: 
            type: String,
        ,
    , ],

   
    mainCategory: 
        type: mongoose.Schema.Types.ObjectId,
        ref: "category",
        required: [true, "It is a required field"],
    ,
    sub1Category: 
        type: mongoose.Schema.Types.ObjectId,
        ref: "category",
        required: [true, "It is a required field"],
    ,
    sub2Category: 
        type: mongoose.Schema.Types.ObjectId,
        ref: "category",
        required: [true, "It is a required field"],
    ,
    createdBy: 
        type: mongoose.Schema.Types.ObjectId,
        ref: "admin",
        required: true,
    ,
    vendor: 
        type: mongoose.Schema.Types.ObjectId,
        ref: "vendor",
    ,
    createdAt: 
        type: String,
        default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
    ,
    updatedAt: 
        type: String,
        default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
    ,
,


    toJson:  virtuals: true ,
    toObject:  virtuals: true ,

);

    productSchema.virtual("reviews", 

ref: "review",

foreignField: "product",

localField: "_id",

// justOne: true
); 

const Product = mongoose.model("product", productSchema);                   
           module.exports = Product;

审查模型

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const moment = require("moment");



const reviewSchema = new Schema(

user: 
    type: mongoose.Schema.Types.ObjectId,
    ref: "user",
    required: [true, "Review must belong to user"],
,
product: 
    type: mongoose.Schema.Types.ObjectId,
    ref: "product",
    required: [true, "Review must belong to the product"],
,
review: 
    type: String,
    required: [true, "Review cannot be empty"],
,
rating: 
    type: Number,
    min: 1,
    max: 5,
,
createdAt: 
    type: String,
    default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
,
updateddAt: 
    type: String,
    default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
,
, 
toJson:  virtuals: true ,
toObject:  virtuals: true ,
);


// pre middleware and populating user and product(we can also do populate in getAllReview in controller)

reviewSchema.pre(/^find/, function(next) 
// ^find here is we use regex and can able to find,findOne ...etc
this.populate(
    path: "product",
    select: " _id name",
).populate(
    path: "user",
    select: " _id fullName",
);
next()
);


const Review = mongoose.model("review", reviewSchema);

module.exports = Review;

在 Review.js 中

const Review = require("../../models/Review.Models")
exports.createReview = async(req, res) => 
const review = await Review.create(req.body)

return res.status(201).json(
    status: true,
    review
)



exports.getAllReviews = async(req, res) => 
try 
    const reviews = await Review.find()

    return res.status(200).json(
        status: true,
        totalReviews: reviews.length,
        reviews
    )
 catch (error) 
    return res.status(400).json(
        status: false,
        error
    )

在 Product.js 中

const Product = require("../../models/Product.Models");
exports.getProductDetailsById = async(req, res) => 
try 
    const  productId  = req.params;

    // const  productId  = req.body;

    if (productId) 
        const products = await Product.findOne( _id: productId )
            .populate('reviews')

        return res.status(200).json(
            status: true,
            products,
        );
     else 
        console.log("error display");
        return res.status(400).json(
            status: false,
            error: "params required...",
        );
    
 catch (error) 
    return res.status(400).json(
        status: false,

        error: error,
    );

【问题讨论】:

在您的架构中,将toJson: virtuals: true 中的json 部分大写-即toJSON: virtuals: true 它没有对此产生任何影响,下面的评论已经解决了我的问题。无论如何,谢谢你伸出援手 当我测试它时它工作得很好......但没关系,因为你似乎已经解决了这个问题。 【参考方案1】:

在 Product.js 中试试这个

 try 
if (productId) 
  const products = await Product.findOne( _id: productId ).populate(
    "reviews"
  );


  console.log(products);
  if (products) 
    return res.status(200).json(
      status: true,
      message: "Products is listed",
      products,
      reviw: products.reviews,
    );

只需要添加响应发送

 return res.status(200).json(
      status: true,
      message: "Products is listed",
      products,
      reviw: products.reviews,
    );

   

【讨论】:

谢谢,真的成功了。另外,我忘记从产品模型中删除 justOne: true 因为这只会显示一条评论。

以上是关于为啥 Virtual Populate 不能在 Node js 和 mongoose 上运行?场景:产品和用户评论的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose 动态模型,不能使用 populate()

字节跳动面试——C++研发工程师

U盘启动winpe安装镜像文件(iso) 不能安装为啥

BeanUtils.populate 的作用

为啥在这个例子中需要后期绑定? [复制]

ModeMongoose 的 Async/Await 与 Mongoose Deep Populate Chain