Mongoose,在子文档数组上应用`.aggregate()`,并以最少的查询次数获得文档其他字段的结果

Posted

技术标签:

【中文标题】Mongoose,在子文档数组上应用`.aggregate()`,并以最少的查询次数获得文档其他字段的结果【英文标题】:Mongoose, apply `.aggregate()` on array of subdocuments and get the result with other fields of document in least number of queries 【发布时间】:2020-11-08 08:27:46 【问题描述】:

这是我的猫鼬模型:

const postSchema = new Schema(
    user: 
        type: Schema.Types.ObjectId,
        ref: 'User',
        required: true
    ,

    caption: 
        type: String
    ,

    action: 
        type: [
            actionName: 
                type: String,
                required: true
            ,
            user: 
                type: Schema.Types.ObjectId,
                ref: 'User'
            
        ],
        default: []
    ,

    shares: [
        type: Schema.Types.ObjectId,
        ref: 'User'
    ];
);

我想要的只是使用或不使用 .aggregate() 的 mongodb 查询来获取 usercaption 字段,而不是 actionshares 我想要他们对特定的计数文件。

示例文档


    _id: "fgsergehegoieofgesfglesfg",

    user: "dfjksjdnfkjsdfkjsdklfjglkbj",

    caption: "This is the post caption",

    action: [
        
            actionName: 'e1', user: "sdfasdsdfasdfdsdfac951e5c"
        ,
        
            actionName: 'e1', user: "asdfmadfadfee103c9c951e5d"
        ,
        
            actionName: 'e2', user: "op34937cdbae0cd4160bbec"
        ,
        
            actionName: 'e2', user: "2543ebbasdfd1750690b5b01c"
        ,
        
            actionName: 'e3', user: "asdfcfebdb5dd1750690b5b01d"
        ,
    ],

    shares: ["ewrebdb5ddadsf5069sadf1d", "asdfsdfbb85dd1750690b5b01c", "fasec92dsfasde103c9c95df5d"]
;

查询后的期望输出:


    _id: "fgsergehegoieofgesfglesfg",
    user: 'dfjksjdnfkjsdfkjsdklfjglkbj',
    caption: 'This is the post caption',
    actionCount: [ count: 1, actionName: 'e3' ,
                  count: 2, actionName: 'e2' ,
                  count: 2, actionName: 'e1' ],
    shareCount: 3

我可以使用.aggregate() 得到以下结果:

查询:

let data = await Test.aggregate([
             $match:  _id: mongoose.Types.ObjectId("fgsergehegoieofgesfglesfg")  ,
             $unwind: "$action" ,
            
                $group: 
                    _id: "$action.actionName",
                    count:  $sum: 1 
                
            ,
            
                $project: 
                    _id: 0,
                    actionName: "$_id",
                    count: 1
                
            
        ]);

结果:

[
   count: 1, actionName: 'e3' ,
   count: 2, actionName: 'e2' ,
   count: 2, actionName: 'e1'  
]

我只是想把这个放在原始文档中并得到结果。此外,对 share 字段执行相同操作。如果这可以在单个查询中完成会更好。我曾尝试使用$replaceRoot$mergeObjects,但不知道如何正确使用它们。我对 mongodb 和 mongoose 很陌生。

请帮忙。谢谢。

【问题讨论】:

【参考方案1】:

由于您正在聚合一个嵌套数组,您需要运行 $grouptwice 和 $first 可用于保留原始文档的字段值:

await Test.aggregate([
     $match:  _id: mongoose.Types.ObjectId("fgsergehegoieofgesfglesfg")  ,
     $unwind: "$action" ,
    
        $group: 
            _id:  _id: "$_id", actionName: "$action.actionName" ,
            user:  $first: "$user" ,
            caption:  $first: "$caption" ,
            count:  $sum: 1 ,
            shareCount:  $first:  $size: "$shares"  
        
    ,
    
        $group: 
            _id: "$_id._id",
            user:  $first: "$user" ,
            caption:  $first: "$caption" ,
            shareCount:  $first: "$shareCount" ,
            actionCount: 
                $push: 
                    actionName: "$_id.actionName",
                    count: "$count"
                
            
        
    
])

Mongo Playground

【讨论】:

非常感谢。这正是我所需要的。但我希望在有 1000 次操作的情况下使用多个 $group 不会过多地增加查询延迟。你能推荐学习 mongodb 的最佳方法吗? @NeetigyaChahar 文档绝对是学习 MongoDB 的最佳途径

以上是关于Mongoose,在子文档数组上应用`.aggregate()`,并以最少的查询次数获得文档其他字段的结果的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬附加在子文档中或子文档本身的数组中

Mongoose:查询参考文档数组上的字段,[重复]

MongoDB/Mongoose 一对多,在子节点中引用父节点 - 分组并加入

Mongoose - 无法在路径 notification.from 上使用排序填充,因为它是文档数组的子属性

如何通过 Mongoose 查询对嵌入文档数组进行排序?

在 Mongoose 中对子文档进行排序