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

如何在MongoDB中使用$lookup运算符添加isOnline状态标识

为聊天参与者填充在线/离线状态的MongoDB聚合方案

背景

开发消息应用时,需要为聊天参与者标注在线/离线状态。当前使用MongoDB的$lookup聚合查询填充参与者信息,但无法正确设置isOnline标识。

数据结构

User Schema:

User {
   _id: ObjectId("123456789xx")
   first_name: "Sam",
   last_name: "Jones",
   email: "samjones@gmail.com",
   inbox: [
      {
          participant: ObjectId("1XXXXXXXXX"),
          added_at: "12:00:00 09/21/2021"
      },
      {
          participant: ObjectId("2XXXXXXXXX"),
          added_at: "12:00:00 11/21/2022"
      },
   ]
}

Session Schema:

Session {
  _id: "XXXuid",
  expire: "12:00:00 07/01/2023",
  session: {
     userId: "1XXXXXXXXX",
     name: "Sam Smith",
     email: "samsmith@gmail.com"
  }
}

说明:已登录用户会存在于Session集合中,通过session.userId关联User的_id。

当前问题

现有$lookup仅能填充参与者基础信息,但无法根据Session判断在线状态:

{
  $lookup: {
     from:"Users",
     localField:"inbox.participant",
     foreignField: "_id",
     as: "participants",
     pipeline:[
       {
          $addField: {
              isOnline: false
          }
       }
     ]
  }
}

解决方案

需要嵌套两次$lookup:先关联User集合获取参与者信息,再关联Session集合判断在线状态,最后将结果映射回inbox数组。完整聚合步骤如下:

db.Users.aggregate([
  // 拆分inbox数组,逐个处理参与者
  { $unwind: "$inbox" },
  // 关联User集合,填充参与者基础信息
  {
    $lookup: {
      from: "Users",
      localField: "inbox.participant",
      foreignField: "_id",
      as: "inbox.participant"
    }
  },
  // 将参与者数组转为单个对象
  { $unwind: "$inbox.participant" },
  // 关联Session集合,检查用户是否有未过期会话
  {
    $lookup: {
      from: "Session",
      let: { userId: "$inbox.participant._id" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ["$session.userId", "$$userId"] },
                // 若expire为字符串格式,需替换为{ $gt: [{ $toDate: "$expire" }, new Date()] }
                { $gt: ["$expire", new Date()] }
              ]
            }
          }
        }
      ],
      as: "inbox.participant.isOnline"
    }
  },
  // 根据Session查询结果设置isOnline布尔值
  {
    $addFields: {
      "inbox.participant.isOnline": {
        $cond: {
          if: { $gt: [{ $size: "$inbox.participant.isOnline" }, 0] },
          then: true,
          else: false
        }
      }
    }
  },
  // 重新组合inbox数组
  {
    $group: {
      _id: "$_id",
      first_name: { $first: "$first_name" },
      last_name: { $first: "$last_name" },
      email: { $first: "$email" },
      inbox: { $push: "$inbox" }
    }
  }
])

关键说明

  • 用$unwind拆分inbox数组,确保每个参与者能单独关联数据
  • 嵌套$lookup先获取用户基础信息,再检查Session集合中是否存在未过期会话
  • 通过$size判断Session查询结果的长度,自动设置isOnline的布尔值
  • 最后用$group将拆分的inbox元素重新组合成数组

最终结果

{
   _id: ObjectId("123456789xx")
   first_name: "Sam",
   last_name: "Jones",
   email: "samjones@gmail.com",
   inbox: [
      {
          participant: {
             first_name:"Sam",
             last_name: "Smith",
             email: "samsmith@gmail.com",
             isOnline: true 
          },
          added_at: "12:00:00 09/21/2021"
      },
      {
          participant: {
             first_name:"Emily",
             last_name: "Grande",
             email: "emilygrande@gmail.com",
             isOnline: false
          },
          added_at: "12:00:00 11/21/2022"
      },
   ]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 04:22:42