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

MongoDB聚合查询问题:匹配非当前用户发送的未读消息

MongoDB聚合查询:检测非自身发送的未读消息问题解决

问题场景

现有用户集合数据结构(简化后):

[
  {
    _id: ObjectId('641b5665894f755f6dc422a2'),
    directMsgs: {
      person1: [
        { authorId: ObjectId('6454bb4e33b90133ba752e96'), isRead: false },
        { authorId: ObjectId('641b5665894f755f6dc422a2'), isRead: true }
      ],
      person2: [
        { authorId: ObjectId('641b5665894f755f6dc422a2'), isRead: true },
        { authorId: ObjectId('642b5765834f755f6dc422b3'), isRead: true }
      ]
    }
  }
]

通过$objectToArray投影后,directMsgs转为键值对数组结构。需求是:查询指定_id的用户是否存在**非自身发送(authorId≠用户_id)且未读(isRead=false)**的消息。

原查询语句在使用$ne操作符时无法正确匹配,去掉该条件或改为$eq时正常。

问题原因

原查询的$match条件是针对整个文档的数组字段,只要directMsgs.v数组中存在任意一个元素满足authorId≠uid,同时存在任意一个元素满足isRead=false,就会匹配文档,但这两个条件可能对应不同的消息对象,不符合“同一个消息同时满足两个条件”的需求。

解决方案

需要先展开嵌套数组,再针对单个消息对象做条件匹配,最后判断是否存在符合条件的消息。以下是两种实现方式:

方式1:直接返回是否存在符合条件的消息

const userId = '641b5665891f755f6dd422a2'
const uid = new ObjectId(userId)

const hasUnreadMsg = await User.aggregate([
  // 先匹配目标用户,减少后续处理数据量
  { $match: { _id: uid } },
  // 将directMsgs对象转为键值对数组
  { $project: { directMsgs: { $objectToArray: '$directMsgs' } } },
  // 展开对话列表
  { $unwind: '$directMsgs' },
  // 展开对话中的消息列表
  { $unwind: '$directMsgs.v' },
  // 匹配符合条件的消息:非自身发送且未读
  { $match: {
    'directMsgs.v.authorId': { $ne: uid },
    'directMsgs.v.isRead': false
  } },
  // 标记存在符合条件的消息
  { $group: { _id: null, exists: { $first: true } } }
])

// 结果判断:若数组长度大于0则存在未读消息
const exists = hasUnreadMsg.length > 0

方式2:返回匹配的消息详情(如果需要)

const userId = '641b5665891f755f6dd422a2'
const uid = new ObjectId(userId)

const matchedMsgs = await User.aggregate([
  { $match: { _id: uid } },
  { $project: { directMsgs: { $objectToArray: '$directMsgs' } } },
  { $unwind: '$directMsgs' },
  { $unwind: '$directMsgs.v' },
  { $match: {
    'directMsgs.v.authorId': { $ne: uid },
    'directMsgs.v.isRead': false
  } },
  // 保留需要的字段
  { $project: {
    conversationKey: '$directMsgs.k',
    authorId: '$directMsgs.v.authorId',
    isRead: '$directMsgs.v.isRead'
  } }
])

// matchedMsgs不为空则存在符合条件的消息

关键优化点

  • 先执行$match筛选目标用户,避免对全集合做后续操作,提升查询效率。
  • 通过两次$unwind展开嵌套数组,将每个消息对象单独处理,确保条件匹配的是同一个消息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 22:25:04