You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mongoose聚合中检测用户投票的Poll选项并返回其ID

解决Mongoose聚合中嵌套数组的用户投票检测问题

我用Mongoose编写了一个聚合管道,用于获取帖子及其关联的点赞、投票数据,通过lookup实现关联。已经通过$in完成了用户是否点赞的检测,但在检测用户投票选项时遇到嵌套对象数组的问题,嵌套$in未生效,希望通过$addFields添加pollVote字段存储用户所选投票选项的ID,避免在控制器中处理逻辑。

现有聚合管道代码

return Post.aggregate([
    {"$match": { "issuer.companyId": new mongoose.Types.ObjectId(startupId) } },
    {"$sort": { "createdAt": -1 } },
    // 点赞检测
    {"$lookup":{
            "from":"postlikes",
            "localField":"_id",
            "foreignField":"_id",
            "as":"likes"
        }},
    {"$addFields": { "likes": {"$first": "$likes.likes._id"}, } },
    {"$addFields": { "liked": {"$in": [ new mongoose.Types.ObjectId(userId), "$likes" ] } } },
    {"$unset": "likes"},
    // 投票检测(待完善)
    {"$lookup":{
            "from":"polls",
            "localField":"_id",
            "foreignField":"_id",
            "as":"polls"
        }},
    {"$addFields": { "polls": {"$first": "$polls.options"}, } },
    // todo: 检测用户ID是否在某个投票数组中,返回选中的选项ID
])

当前输出结果

[
     {
         "_id": "6414698183b285f6f16a17be",
         "poll": [
             {
                 "text": "Facebook",
                 "votes": 0,
                 "_id": "6414698183b285f6f16a17c0"
             },
             {
                 "text": "TikTok",
                 "votes": 2,
                 "_id": "6414698183b285f6f16a17c1"
             }
         ],
         "liked": true,
         "polls": [
             {
                 "_id": "6414698183b285f6f16a17c0", 
                 "voters": []
             },
             {
                 "_id": "6414698183b285f6f16a17c1",
                 "voters": [
                     {
                         "name": "XX",
                         "timestamp": 1679218784,
                         "_id": "63d3892fd1cc6b5711c67799"
                     }
                 ]
             }
         ]
     },
]

预期输出结果

[
     {
         "_id": "6414698183b285f6f16a17be",
         "poll": [
             {
                 "text": "Facebook",
                 "votes": 0,
                 "_id": "6414698183b285f6f16a17c0"
             },
             {
                 "text": "TikTok",
                 "votes": 2,
                 "_id": "6414698183b285f6f16a17c1"
             }
         ],
         "liked": true,
         "pollVote": "6414698183b285f6f16a17c1" // 用户投了TikTok选项
     },
]

解决方案

通过$filter筛选包含当前用户的投票选项,结合$map提取投票者ID数组,再用$arrayElemAt获取匹配选项的ID,最后清理临时字段。修改后的聚合管道如下:

return Post.aggregate([
    {"$match": { "issuer.companyId": new mongoose.Types.ObjectId(startupId) } },
    {"$sort": { "createdAt": -1 } },
    // 点赞检测部分保持不变
    {"$lookup":{
            "from":"postlikes",
            "localField":"_id",
            "foreignField":"_id",
            "as":"likes"
        }},
    {"$addFields": { "likes": {"$first": "$likes.likes._id"}, } },
    {"$addFields": { "liked": {"$in": [ new mongoose.Types.ObjectId(userId), "$likes" ] } } },
    {"$unset": "likes"},
    // 投票检测修改部分
    {"$lookup":{
            "from":"polls",
            "localField":"_id",
            "foreignField":"_id",
            "as":"polls"
        }},
    {"$addFields": { "polls": {"$first": "$polls.options"}, } },
    // 筛选包含当前用户的投票选项
    {"$addFields": {
        "pollVote": {
            "$arrayElemAt": [
                {"$filter": {
                    "input": "$polls",
                    "as": "option",
                    "cond": {
                        "$in": [
                            new mongoose.Types.ObjectId(userId),
                            {"$map": {
                                "input": "$$option.voters",
                                "as": "voter",
                                "in": "$$voter._id"
                            }}
                        ]
                    }
                }},
                0
            ]
        }
    }},
    // 提取选项ID,未投票则返回null
    {"$addFields": {
        "pollVote": {"$ifNull": ["$pollVote._id", null]}
    }},
    // 移除临时polls字段
    {"$unset": "polls"}
])

关键逻辑说明

  1. $map + $in:将每个投票选项的voters数组转换为仅包含用户ID的数组,再用$in判断当前用户是否在其中。
  2. $filter:筛选出符合条件的投票选项(一个用户仅能投一个选项)。
  3. $arrayElemAt:取出筛选结果的第一个元素,确保只获取用户的投票选项。
  4. $ifNull:处理用户未投票的场景,此时pollVote设为null。

内容的提问来源于stack exchange,提问作者Jakob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:23:22