【问题标题】:Mongoose Virtual - Count references in another model that are in local array of referencesMongoose Virtual - 计算本地引用数组中另一个模型中的引用
【发布时间】:2022-02-01 22:39:36
【问题描述】:

我有 2 个模型CommentReport

const mongoose = require('mongoose');

const CommentSchema = new mongoose.Schema(
    {
        content: {
            type: String,
            trim: true,
            maxLength: 2048,
        },
        createdAt: {
            type: Date,
            default: Date.now,
        },
        parent: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Comment',
            required: false,
        },
        replies: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'Comment',
            },
        ],
        isReply: {
            type: Boolean,
            default: false,
        },
    },
    { toJSON: { virtuals: true }, toObject: { virtuals: true } }
);

CommentSchema.virtual('reportCount', {
    ref: 'Report',
    localField: '_id',
    foreignField: 'comment',
    justOne: false,
    count: true,
});

CommentSchema.virtual('reportReplyCount', {
    ref: 'Report',
    localField: 'replies',
    foreignField: 'comment',
    justOne: false,
    count: true,
});

module.exports = mongoose.model('Comment', CommentSchema);

Comment 具有字段回复,它是指向 Comment 模型的引用数组。用户可以报告评论,当发生这种情况时,新的报告文档会存储在报告集合中,并且它包含对该评论的引用和对用户的引用。我在评论架构中有 2 个虚拟属性,reportCount(显示该评论的报告数量)和 reportReplyCount(显示评论回复的报告数量)。现在 reportCount 可以完美运行,但 reportReplyCount 却不行。当我创建评论以及对该评论的回复时,它会显示回复数量而不是报告数量。我用谷歌搜索但找不到类似的东西。

const mongoose = require('mongoose');
    
    const ReportSchema = new mongoose.Schema({
        description: {
            type: String,
            trim: true,
            required: true,
            maxLength: 100,
        },
        reporter: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User',
            required: true,
        },
        createdAt: {
            type: Date,
            default: Date.now,
        },
        comment: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Comment',
            required: true,
        },
    });
    
    
    module.exports = mongoose.model('Report', ReportSchema);

【问题讨论】:

    标签: node.js express mongoose mongoose-schema mongoose-populate


    【解决方案1】:

    我不知道你到底想做什么,但我环顾四周,似乎没有任何现有的解决方案。虚拟是解决问题的一种方法,但我还没有看到在这种情况下使用它的答案。

    您可以尝试创建一个名为 reportReplyCount 的新虚拟,以显示回复报告的数量。然后在评论中使用aggregate 并将reportCount 替换为新的虚拟。您可以使用以下内容:

    CommentSchema.virtual('reportReplyCount', {
        ref: 'Report', // reference to Report model
        localField: 'replies', // matches field Comment Schema has named 'replies' 
        foreignField: 'comment', // matches field Report Schema has named 'comment' (foreign key in Report model) 
        justOne: false, // this is going to return all related documents, not just one (just like reportCount)  
        count: true, // set it to true so it returns a number instead of an array of documents  
    });
    
        CommentSchema.methods = { ... }
    
        CommentSchema.statics = { ... }
    
         module.exports = mongoose.model('Comment', CommentSchema);
    
    

    如果您能为您的问题找到另一种解决方案,我会避免在您的情况下使用虚拟机。

    顺便说一句,我看到开发人员创建了一个新模型来充当虚拟模型,如下所示:

    const mongoose = require('mongoose');
    
       const ReportSchema = new mongoose.Schema({
           description: {
               type: String,
               trim: true,
               required: true,
               maxLength: 100,
           },
           reporter: { // reference to User model (foreign key) 
               type: mongoose.Schema.Types.ObjectId, 
               ref: 'User',  // reference to User model (foreign key) 
    
       });
    
       module.exports = mongoose.model('Report', ReportSchema);
    
       // Now you need an instance of that new Schema called VirtualReport. The schema must follow the same format as the "real" Report's schema did above but with a few extra parameters that refer to the virtual and it's definition (as in how it will behave). 
    
       const VirtualReportSchema = new mongoose.Schema({ ... }, { _id : false });
    
       module.exports = mongoose.model('VirtualReport', VirtualReportSchema);
    
    

    那么你需要做的就是,在你的架构中有虚拟:

       // Now you can use VirtualReport like any other model. It will work just like Report but it won't get stored in the database. 
       CommentSchema.virtual('reportReplyCount', {
           ref: 'VirtualReport', // reference to VirtualReport model 
           localField: 'replies', // matches field Comment Schema has named 'replies' 
           foreignField: 'comment', // matches field VirtualReport Schema has named 'comment' (foreign key in VirtualReport model) 
           justOne: false, // this is going to return all related documents, not just one (just like reportCount)  
           count: true, // set it to true so it returns a number instead of an array of documents  
       });
    
       CommentSchema.methods = { ... }
    
       CommentSchema.statics = { ... }
    
        module.exports = mongoose.model('Comment', CommentSchema);
    
    

    但请注意,虚拟的定义(“它将如何表现”)必须包含设置为 false 的 _id 属性(否则将引发错误)。这是因为当子文档中使用虚拟对象并且用户通过点符号(例如,commentToBeDeleted[parent].reportReplyCount)引用它们时,点符号会尝试访问虚拟的 _id 属性。如果它设置为 false,点表示法将无法找到该虚拟,并且您将收到错误消息。所以不要忘记将_id属性设置为false!

    顺便说一句,有人问过这个问题here。不幸的是,这个问题是在 Stack Overflow 上提出的,而不是在 MongoDB 自己的文档中提出的,其中提供了对虚拟的解释的链接(还有关于“justOne”的评论,但至少它直接引用了文档)。

    【讨论】:

    • 为 Virtuals 添加架构只会使事情变得更加复杂,并且不能回答我的问题。我只想计算存储在参考数组中的评论回复的报告数量。我的猜测是任何一个引用数组都不能被引用到 virtual 中的单个 ref,或者 mongoose 中存在错误。
    • 虚拟不应该使事情复杂化,只要你不需要在猫鼬之外使用它。您可以简单地在模型上创建一个方法/属性来获取报告的数量。如果没有报告,您可以返回 0 或不定义。
    猜你喜欢
    • 2015-12-13
    • 2013-08-02
    • 2015-05-12
    • 2020-09-26
    • 2022-01-21
    • 2021-07-31
    • 1970-01-01
    • 2021-09-08
    • 2011-05-13
    相关资源
    最近更新 更多