【问题标题】:mongoDB find document greatest date and check valuemongoDB查找文档最大日期并检查值
【发布时间】:2016-02-05 21:11:02
【问题描述】:

我有一个如下所示的对话集合:

[
  {
    "_id": "QzuTQYkGDBkgGnHrZ",
    "participants": [
      {
        "id": "YymyFZ27NKtuLyP2C"
      },
      {
        "id": "d3y7uSA2aKCQfLySw",
        "lastVisited": "2016-02-04T02:59:10.056Z",
        "lastMessage": "2016-02-04T02:59:10.056Z"
      }
    ]
  },
  {
    "_id": "e4iRefrkqrhnokH7Y",
    "participants": [
      {
        "id": "d3y7uSA2aKCQfLySw",
        "lastVisited": "2016-02-04T03:26:33.953Z",
        "lastMessage": "2016-02-04T03:26:53.509Z"
      },
      {
        "id": "SRobpwtjBANPe9hXg",
        "lastVisited": "2016-02-04T03:26:35.210Z",
        "lastMessage": "2016-02-04T03:15:05.779Z"
      }
    ]
  },
  {
    "_id": "twXPHb76MMxQ3MQor",
    "participants": [
      {
        "id": "d3y7uSA2aKCQfLySw"
      },
      {
        "id": "SRobpwtjBANPe9hXg",
        "lastMessage": "2016-02-04T03:27:35.281Z",
        "lastVisited": "2016-02-04T03:57:51.036Z"
      }
    ]
  }
]

每个对话(文档)都可以有一个参与者对象,其属性为idlastMessagelastVisited

有时,根据对话的新鲜程度,其中一些值还不存在(例如lastMessagelastVisited)。

我要做的是比较每个单独对话(文档)中的每个参与者,看看是否在所有参与者中,最大的 lastMessage 字段值属于登录用户。否则,我假设对话中包含登录用户尚未看到的消息。我想获取用户可能尚未看到的消息数。

在上面的示例中,假设我们以d3y7uSA2aKCQfLySw 登录。我们可以看到他是最后一个发送消息进行对话的人1, 2 但不是3d3y7uSA2aKCQfLySw 没有看到的更新对话的返回计数应该是 1。

有人能指出我正确的方向吗?我对如何解决这个问题一无所知。对于这个冗长的问题,我深表歉意。

【问题讨论】:

    标签: mongodb meteor


    【解决方案1】:

    始终建议将日期存储为ISODate 而不是字符串,以利用aggregation 框架中各种date operators 提供的灵活性。

    获得计数的一种方法是,

    • $match 用户参与的对话。
    • $unwind participants 字段。
    • $sortlastMessage 字段按降序排列
    • $group 通过_id 恢复原始对话,并使用$first 运算符获取每个组(对话)的最新消息。
    • $project 一个值为 0 的字段,用于每个组,其中最高记录是我们正在寻找的用户,1 是其他用户。
    • 再次$group 以获取他不是最后一个发送消息的对话的总数。

    示例代码:

    var userId = "d3y7uSA2aKCQfLySw"; 
    db.t.aggregate([
     {
        $match:{"participants.id":userId}
     },
     {
        $unwind:"$participants"
     },
     {
        $sort:{"participants.lastMessage":-1}
     },
     {
        $group:{"_id":"$_id","lastParticipant":{$first:"$$ROOT.participants"}}
     },
     {
        $project:{
       "hasNotSeen":{$cond:[
                             {$eq:["$lastParticipant.id",userId]},
                             0,
                             1
                           ]},
       "_id":0}
     },
     {
        $group:{"_id":null,"count":{$sum:"$hasNotSeen"}}
     },
     {
        $project:{"_id":0,"numberOfConversationsNotSeen":"$count"}
     }
    ])
    

    【讨论】:

    • 感谢您的回答,它可以满足我的需求。但是问题是,这样的事情可以在没有聚合的情况下完成吗?我正在使用 MeteorJS,对我来说,最重要的是一切都在实时工作(反应式)。不幸的是,this 包为我提供了使用聚合的能力限制了反应性。
    【解决方案2】:

    我想试试这个功能。

    function findUseen(uId) {
        var numMessages = db.demo.aggregate(
            [
                {
                    $project: {
                        "participants.lastMessage": 1,
                        "participants.id": 1
                    }
                },
                {$unwind: "$participants"},
                {$sort: {"participants.lastMessage": -1}},
                {
                    $group: {
                        _id: "$_id",
                        participantsId: {$first: "$participants.id"},
                        lastMessage: {$max: "$participants.lastMessage"}
                    }
                },
                {$match: {participantsId: {$ne: uId}}},
            ]
        ).toArray().length;
    
        return numMessages;
    }
    

    调用 findUnseen("d3y7uSA2aKCQfLySw") 将返回 1。

    我采用此函数只是为了返回计数,但正如您所见,调整它以返回所有未见过的消息元数据也很容易。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-01
      • 2016-04-23
      • 2021-11-10
      • 2015-05-03
      • 1970-01-01
      • 1970-01-01
      • 2019-03-21
      • 1970-01-01
      相关资源
      最近更新 更多