从MongoDB中的同一数组返回包含两个字段的文档

时间:2018-11-21 15:55:05

标签: mongodb mongodb-query aggregation-framework

给出诸如

的文档
{
  _id: 'abcd',
  userId: '12345',
  activities: [
    { status: 'login', timestamp: '10000001' },
    { status: 'logout', timestamp: '10000002' },
    { status: 'login', timestamp: '10000003' },
    { status: 'logout', timestamp: '10000004' },
  ]
}

我正在尝试创建一个管道,例如将返回在两个时间戳之间记录有最新登录/注销活动的所有用户。例如,如果两个时间戳值在1000000210000003之间,则预期文档应为

{
  _id: 'abcd',
  userId: '12345',
  login: '10000003',
  logout: '10000002'
}

如果两个时间戳值在-110000001之间,则预期文档应为:

{
  _id: 'abcd',
  userId: '12345',
  login: '10000001',
  logout: null
}

等等。

我知道它与聚合有关,我需要$unwind,依此类推,但是我不确定其余的事情,即评估同一文档数组中的两个字段

2 个答案:

答案 0 :(得分:1)

您可以尝试以下汇总:

db.col.aggregate([
    { 
        $unwind: "$activities" 
    },
    {
        $match: {
            $and: [
                { "activities.timestamp": { $gte: "10000001" } },
                { "activities.timestamp": { $lte: "10000002" } }
            ]
        }
    },
    {
        $sort: {
            "activities.timestamp": -1
        }
    },
    {
        $group: {
            _id: "$_id",
            userId: { $first: "$userId" },
            activities: { $push: "$activities" }
        }
    },
    {
        $addFields: {
            login: { $arrayElemAt: [ { $filter: { input: "$activities", as: "a", cond: { $eq: [ "$$a.status", "login" ] } } } , 0 ] },
            logout: { $arrayElemAt: [ { $filter: { input: "$activities", as: "a", cond: { $eq: [ "$$a.status", "logout" ] } } } , 0 ] }
        }
    },
    {
        $project: {
            _id: 1,
            userId: 1,
            login: { $ifNull: [ "$login.timestamp", null ] },
            logout: { $ifNull: [ "$logout.timestamp", null ] }
        }
    }
])

我们需要使用$unwind + $sort + $group来确保我们的活动将按时间戳进行排序。在$unwind之后,您可以使用$match来应用过滤条件。然后,您可以将$filter$arrayElemAt一起使用,以获取过滤后的数组的第一个(最新)值。在最后一个$project中,您可以显式使用$ifNull(否则,如果没有值,JSON密钥将被跳过)

答案 1 :(得分:1)

您可以使用以下汇总

$unwind$lte$gte聚合一起使用,而不是$fitler

db.collection.aggregate([
  { "$project": {
    "userId": 1,
    "login": {
      "$max": {
        "$filter": {
          "input": "$activities",
          "cond": {
            "$and": [
              { "$gte": ["$$this.timestamp", "10000001"] },
              { "$lte": ["$$this.timestamp", "10000004"] },
              { "$lte": ["$$this.status", "login"] }
            ]
          }
        }
      }
    },
    "logout": {
      "$max": {
        "$filter": {
          "input": "$activities",
          "cond": {
            "$and": [
              { "$gte": ["$$this.timestamp", "10000001"] },
              { "$lte": ["$$this.timestamp", "10000004"] },
              { "$lte": ["$$this.status", "logout"] }
            ]
          }
        }
      }
    }
  }}
])