MongoDB中两个集合的查询

MongoDB中两个集合的查询,mongodb,mongodb-query,Mongodb,Mongodb Query,我想在MongoDB找到我的路。这是我第一次使用这个数据库,来自MySQL。但对于我正在开发的聊天应用程序,MongoDB被推荐为更合适的 我有两个收藏: 对话其中我存储了成员用户ID(存储在MySQL数据库中)和加入日期 { "_id" : ObjectId("5e35f2c840713a43aeeeb3d9"), "members" : [ { "uID" : "1", "j" : 1580580922

我想在MongoDB找到我的路。这是我第一次使用这个数据库,来自MySQL。但对于我正在开发的聊天应用程序,MongoDB被推荐为更合适的

我有两个收藏:

对话其中我存储了成员用户ID(存储在MySQL数据库中)和加入日期

{
    "_id" : ObjectId("5e35f2c840713a43aeeeb3d9"),
    "members" : [ 
        {
            "uID" : "1",
            "j" : 1580580922
        }, 
        {
            "uID" : "4",
            "j" : 1580580922
        }, 
        {
            "uID" : "5",
            "j" : 1580580922
        }
    ]
}
消息其中存储发件人(用户ID)、消息、时间戳、会话ID(来自上述集合)、已读和已送达状态

{
    "_id" : ObjectId("5e35ee5f40713a43aeeeb1c5"),
    "c_ID" : ObjectId("5e35f2c840713a43aeeeb3d9"),
    "fromID" : "1",
    "msg" : "What's up?",
    "t" : 1580591922,
    "d" : {
        "4" : 1580592039
    },
    "r" : {
        "4" : 1580592339
    }
}
我现在要做的是查询特定用户的对话,比如userID 1,以及该对话中发送的最后一条消息

我得出了以下结论:

db.getCollection('conversations').aggregate(
[{
    $match: {
        "members.uID": "1"
    }
},
{
    $lookup: {
        as: 'lastMessage',
        foreignField: 'c_ID',
        from: 'messages',
        localField: '_id',
    }
},
])
但这里的问题是,它列出了所有消息,而不仅仅是最后一条。因此,我想将其限制为1,或者如果有其他方法。。请让我知道


感谢您的帮助

我想我们可以理解时间戳字段中的最后一条消息

$match
$lookup
阶段之后,我们需要先查看消息,然后再查看时间戳

现在messages数组中的第一条消息是lastMessage,因此当我们将第一条消息作为lastMessage推送时,我们将最终形成我们的结果

如果是这样,您可以使用以下聚合:

db.conversations.aggregate([
  {
    $match: {
      "members.uID": "1"
    }
  },
  {
    $lookup: {
      foreignField: "c_ID",
      from: "messages",
      localField: "_id",
      as: "messages"
    }
  },
  {
    "$unwind": "$messages"
  },
  {
    "$sort": {
      "messages.t": -1
    }
  },
  {
    "$group": {
      "_id": "$_id",
      "lastMessage": {
        "$first": "$messages"
      },
      "allFields": {
        "$first": "$$ROOT"
      }
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        "$mergeObjects": [
          "$allFields",
          {
            "lastMessage": "$lastMessage"
          }
        ]
      }
    }
  },
  {
    $project: {
      messages: 0
    }
  }
])
如果消息数组已经排序,则可以简化解决方案,但这是一个通用解决方案


如果您不受这些特定模式的约束,我建议将消息存储为会话中的数组。这将大大简化您想要执行的任何聚合查询,以查找对话中的特定消息(无论是第一条消息、最近的消息、来自某个用户的所有消息,等等)。这可能更适合您的聊天应用程序使用对话和消息的方式。本质上,这消除了在会话中查找消息所需的“连接”。我确实考虑过,但是每次添加消息时,我都需要执行更新。这不是很有效,是吗?插入可能比更新快,但如果您使用_id更新对话,并且只添加新消息,则插入可能不会太快。我认为将消息包含在对话中的好处大于写入性能稍慢的好处:您的数据结构更自然,在概念上更易于处理,并且读取性能也得到了提高,因为现在您不再需要对DB进行两次调用,应用程序就可以加载对话(1获取对话,然后1获取对话中的所有消息)。下面的解决方案是否不好?另外,如果有很多消息,保留所有ID可能会达到16mb的限制,不是吗?我看到下面的解决方案没有任何问题(尽管我已经有一段时间没有做过大量的聚合)您可以通过大量消息进入文档大小限制,因此,如果这是一个现实的问题,我会考虑保留一个名为OLD消息的单独集合:该集合中的每个对象包含一个消息数组,并且可选地,在OLD消息中的另一个对象的一个ID,用于更旧的消息。e一个“oldMessages”字段,如果存在该字段,它是在已经存在的消息之后的下一个最旧消息集的id。似乎做了我想做的事情!我只剩下,我现在有消息和lastMessage,包含相同的数据。我可以“隐藏”吗或者删除messages对象?或者是否需要它来执行查询?@PennyWise您可以使用stage轻松删除不需要的字段,我更新了答案。请不要忘记标记此答案并向上投票。我似乎错过了更新答案中的project stage。您能再添加一次吗?