虚拟填充猫鼬

Posted

技术标签:

【中文标题】虚拟填充猫鼬【英文标题】:Virtual populate mongoose 【发布时间】:2021-01-09 21:06:03 【问题描述】:

我尝试在我创建的两个模型之间使用虚拟填充: 在这种情况下,获取带有游览 ID 的所有评论并与游览一起显示。 (当使用查询 findById() 仅显示此游览时)

我的虚拟在架构中设置为 true(我尝试在使用虚拟填充后将它们设置为 true,但它不起作用 - 通过 soultion)

在检查了 mongoose 文档后,它似乎是正确的,但它不起作用。

我的游览架构:

const tourSchema = new mongoose.Schema(
    name: 
        type: String,
        required: [true, 'A tour must have a name'], //validator
        unique: true,
        trim: true,
        maxlength: [40, 'A tour name must have less or equal then 40 characters'],
        minlength: [10, 'A tour name must have at least 10 character']
        //validate: [validator.isAlpha, 'A tour name must have only alphabetic characters']
    ,

    etc...
    etc...
    etc...

    //guides: Array --- array of user id's || embedding
    guides: [ 
        //Reference to the user data model without saving the guides in the tour data model
        //Child referencing
        
            type: mongoose.Schema.ObjectId,
            ref: 'User'
        
    ]
,
    
        //passing options, getting the virual properties to the document/object
        toJSON:  virtuals: true ,
        toObject:  virtuals: true 
    
);

//Define virtual properties
tourSchema.virtual('durationWeeks').get(function () 
    console.log('Virtual 1');
    //using function declaration => using this keyword
    return this.duration / 7;
);

//Virtual populate
tourSchema.virtual('reviews', 
    ref: 'review',
    localField: '_id', // Find tour where `localField`
    foreignField: 'tour', // is equal to `foreignField`
    //look for the _id of the tour in the tour field in review
);

我的评论架构: ** 我在巡演的审核模式中使用,并为巡演 ID 填充用户 **

const reviewSchema = new mongoose.Schema(
    review: 
        type: String,
        required: [true, 'Review can not be empty!']
    ,
    rating: 
        type: Number,
        min: 1,
        max: 5
    ,
    createdAt: 
        type: Date,
        default: Date.now(),
    ,
    tour: [
        
            type: mongoose.Schema.ObjectId,
            ref: 'Tour',
            required: [true, 'Review must be belong to a tour.']
        
    ],
    user: [
        
            type: mongoose.Schema.ObjectId,
            ref: 'User',
            required: [true, 'Review must be belong to a user.']
        
    ]
,
    
        //passing options, getting the virual properties to the document/object
        toJSON:  virtuals: true ,
        toObject:  virtuals: true ,
    
);


//Query middleware
reviewSchema.pre(/^find/, function (next) 
    this.populate(
        path: 'tour',
        select: 'name'
    )
        .populate(
            path: 'user',
            select: 'name'
        );

    next();
);

我的输出: 获取所有评论(查看模型数据):


    "status": "success",
    "data": 
        "review": [
            
                "_id": "5f6ba5b45624454efca7e0b1",
                "review": "What an amzing tour",
                "tour": 
                    "guides": [],
                    "_id": "5c88fa8cf4afda39709c2955",
                    "name": "The Sea Explorer",
                    "durationWeeks": null,
                    "id": "5c88fa8cf4afda39709c2955"
                ,
                "user": 
                    "_id": "5f69f736e6eb324decbc3a52",
                    "name": "Liav"
                ,
                "createdAt": "2020-09-23T19:44:52.519Z",
                "id": "5f6ba5b45624454efca7e0b1"
            
        ]
    

以及通过 id 获取游览:


    "status": "success",
    "data": 
        "tour": 
            "startLocation": 
                "type": "Point",
                "coordinates": [
                    -80.185942,
                    25.774772
                ],
                "description": "Miami, USA",
                "address": "301 Biscayne Blvd, Miami, FL 33132, USA"
            ,
            "ratingsAverage": 4.8,
            "ratingsQuantaity": 0,
            "images": [
                "tour-2-1.jpg",
                "tour-2-2.jpg",
                "tour-2-3.jpg"
            ],
            "startDates": [
                "2021-06-19T09:00:00.000Z",
                "2021-07-20T09:00:00.000Z",
                "2021-08-18T09:00:00.000Z"
            ],
            "secretTour": false,
            "guides": [],
            "_id": "5c88fa8cf4afda39709c2955",
            .
            .
            .
            .
            "slug": "the-sea-explorer",
            "__v": 0,
            "durationWeeks": 1,
            "id": "5c88fa8cf4afda39709c2955"
        
    

您可以看到评论将游览作为 arr 并且 id 在游览的 arr 内是否存在填充未针对正确字段的选项?

【问题讨论】:

【参考方案1】:

所以我想通了。 首先我在 github - mongoose repo 中询问并得到了回答:

reviewSchema.pre(/^find/, function (next) 
    this.populate(
        path: 'tour',
        options:  select: 'name'  // <-- wrap `select` in `options` here...
    ).populate(
        path: 'user',
        options:  select: 'name photo'  // <-- and here
    );

    next();
);

我们应该改进这一点:嵌套选项非常令人困惑,而且 很难记住应该是 options.select 还是 select

第二个问题是在游览控制器中使用 FindById 方法后添加填充,使用填充而不使用包装“选择”对我不起作用。

exports.getTour = catchAsync(async (req, res, next) =>  //parameter => :id || optinal parameter => :id?
    //populate reference to the guides in the user data model
    const tour = await Tour.findById(req.params.id).populate('reviews');

    if (!tour) 
        return next(new AppError('No tour found with that id', 404));
    

    res.status(200).json(
        status: 'success',
        data: 
            tour
        
    );
)

在游览模型中,我将外键从“tour_id”更改(正如我在其他问题中看到的那样)。

//Virtual populate
tourSchema.virtual('reviews', 
    ref: 'Review',
    localField: '_id', // Find tour where `localField`
    foreignField: 'tour' // is equal to `foreignField`
    //look for the _id of the tour in the tour field in review
);

现在我的旅游数据中确实有评论,它确实通过 id 虚拟填充到旅游中

【讨论】:

【参考方案2】:

您需要将选项virtuals: true 传递到架构创建中:

const tourSchema = new mongoose.Schema(
    ...
, 
  virtuals: true

此外,我们使用mongoose-lean-virtuals 模块来帮助处理 .lean 和 virtuals。例如

const mongooseLeanVirtuals = require('mongoose-lean-virtuals');
...
tourSchema.plugin(mongooseLeanVirtuals);
tourSchema.set('toJSON',  virtuals: true );
tourSchema.set('toObject',  virtuals: true );

虽然我猜这不是绝对必要的。

【讨论】:

嘿,那没用,在我的 tourSchema 中你也可以看到,在定义模型后将 virtuals 设置为 true。此外,我更新了问题并发布了我得到回复的 JSON。在 reviewSchema 中,我得到了游览的 id,但在游览对象的 arr 中,我可能无法正确填充来获取 id?

以上是关于虚拟填充猫鼬的主要内容,如果未能解决你的问题,请参考以下文章

仅获取猫鼬虚拟填充的长度

无法在 NestJS 应用程序中启动并运行猫鼬虚拟填充

猫鼬'填充'不填充

猫鼬填充未填充必填字段

猫鼬填充功能不填充

为啥需要猫鼬填充?