mongodb聚合从子文档中获取查询的最后一个对象

时间:2019-06-03 09:14:32

标签: mongodb mongodb-query aggregation-framework

我们在mongodb中存储了以下文档集:

对话记录

{_id: "x", lang: "en", timestamp: "", ... }

每个会话都有许多进程,每个进程都有一组消息作为子文档列表。 处理记录:

{_id: "y", conversationId: "x", name: "", timestamp: "", messages: [
    {
        "direction" : "out",
        "text" : "How can I help you?",
        "timestamp" : ISODate("2019-05-23T11:08:18.423Z"),
        "_id" : 3
    },
    {
        "direction" : "out",
        "text" : "Hello",
        "timestamp" : ISODate("2019-05-23T11:08:17.423Z"),
        "_id" : 1
    },
    {
        "direction" : "in",
        "text" : "Hi",
        "timestamp" : ISODate("2019-05-23T11:08:18.423Z"),
        "_id" : 2
    }
], completed: "true"}

我需要进行aggregate查询,并获取对话列表,而每个对话都应具有按时间戳排序的进程列表,并且每个进程应仅具有 last 消息( (从“入”和“出”两个方向的“ strong>基于ID字段)。

我们需要得到这样的东西:

[
  {
    conversationId: "x",
    timestamp: "",
    processes: [
      {
        _id: "y",
        name: "",
        timestamp: "",
        lastInMessage: {
          "direction": "in",
          "text": "Hi",
          "timestamp": ISODate("2019-05-23T11:08:18.423Z"),
          "_id": 2
        },
        lastOutMessage: {
          "direction": "out",
          "text": "How can I help you?",
          "timestamp": ISODate("2019-05-23T11:08:18.423Z"),
          "_id": 3
        }
      },
      {
        _id: "y",
        name: "",
        ....
      }
    ]
  }
]

我尝试过的查询是:

conversation.aggregate([
        {
            $match: {
                timestamp: query.timestamp
            }
        },
        {
            $project: {
                _id: "$conversationId",
                timestamp: "$timestamp",
                conversationId: "$conversationId"
            }
        },
        {
            "$lookup":
                {
                    "from": "processes",
                    "localField": "conversationId",
                    "foreignField": "conversationId",
                    "as": "process"
                }
        },
        {
            $project: {
                _id: "$_id",
                timestamp: "$timestamp",
                // messages: "$process.messages",
                processes: "$process"
            }
        },
       // here I don't know what to do.

1 个答案:

答案 0 :(得分:1)

您可以使用$reduce来计算数组的最小值和最大值,并可以使用$map来生成所有process值的集合:

{
    $project: {
        _id: "$_id",
        timestamp: "$timestamp",
        processes: {
            $map: {
                input: "$processes",
                as: "process",
                in: {
                    _id: "$$process._id",
                    name: "$$process.name",
                    timestamp: "$$process.timestamp",
                    lastInMessage: {
                        $reduce: {
                            input: "$$process.messages",
                            initialValue: null,
                            in: {
                                $cond: [
                                    { $and: [ { $eq: [ "$$this.direction", "in" ] }, { $gt: [ "$$this.timestamp", "$$value.timestamp" ] } ] },
                                    "$$this",
                                    "$$value"
                                ]
                            }
                        }
                    },
                    lastOutMessage: {
                        $reduce: {
                            input: "$$process.messages",
                            initialValue: null,
                            in: {
                                $cond: [
                                    { $and: [ { $eq: [ "$$this.direction", "out" ] }, { $gt: [ "$$this.timestamp", "$$value.timestamp" ] } ] },
                                    "$$this",
                                    "$$value"
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}

MongoDB Playground example