【问题标题】: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 内是否存在填充未针对正确字段的选项?

【问题讨论】:

    标签: javascript node.js mongoose


    【解决方案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?
      猜你喜欢
      • 2017-04-04
      • 2020-05-18
      • 2018-12-23
      • 1970-01-01
      • 2015-07-13
      • 2016-10-10
      • 2021-09-19
      • 2019-09-16
      相关资源
      最近更新 更多