MongoDB按ID分组,然后按日期分组

时间:2019-01-11 08:59:20

标签: node.js mongodb mongoose aggregation-framework aggregate

我在MongoDB数据库中有一个集合,该集合存储分组用户的持续时间,如下所示:

[{
    "_id": "5c378eecd11e570240a9b0ac",
    "state": "DRAFT",
    "groupId": "5c378eebd11e570240a9ae49",
    "personId": "5c378eebd11e570240a9aee1",
    "date": "2019-01-07T00:00:00.000Z",
    "duration": 480,
    "__v": 0
},
{
    "_id": "5c378eecd11e570240a9b0bb",
    "state": "DRAFT",
    "groupId": "5c378eebd11e570240a9ae58",
    "personId": "5c378eebd11e570240a9aeac",
    "date": "2019-01-07T00:00:00.000Z",
    "duration": 480,
    "__v": 0
},
{
    "_id": "5c378eecd11e570240a9b0c5",
    "state": "DRAFT",
    "groupId": "5c378eebd11e570240a9ae3e",
    "personId": "5c378eebd11e570240a9aef6",
    "date": "2019-01-07T00:00:00.000Z",
    "duration": 480,
    "__v": 0
}]

我希望能够运行一个聚合查询,该查询返回personIdsduration的集合,该集合每天与相应的groupId分组,如下所示:< / p>

[{
    "personId": "5c378eebd11e570240a9aee1",
    "time": [{
        "date": "2019-01-07T00:00:00.000Z",
        "entries": [{
            "groupId": "5c378eebd11e570240a9ae49",
            "duration": 480,
            "state": "DRAFT"
        }]
    }]
}, {
    "personId": "5c378eebd11e570240a9aeac",
    "time": [{
        "date": "2019-01-07T00:00:00.000Z",
        "entries": [{
            "groupId": "5c378eebd11e570240a9ae58",
            "duration": 480,
            "state": "DRAFT"
        }]
    }]
}, {
    "personId": "5c378eebd11e570240a9aef6",
    "time": [{
        "date": "2019-01-07T00:00:00.000Z",
        "entries": [{
            "groupId": "5c378eebd11e570240a9ae3e",
            "duration": 480,
            "state": "DRAFT"
        }]
    }]
}]

到目前为止,我已经编写了以下汇总(我使用的是Mongoose,因此使用了语法):

Time.aggregate()
    .match({ date: { $gte: new Date(start), $lte: new Date(end) } })
    .group({
      _id: '$personId',
      time: { $push: { date: '$date', duration: '$duration', state: '$state' } },
    })
    .project({ _id: false, personId: '$_id', time: '$time' })

哪个返回以下内容:

[{
    "personId": "5c378eebd11e570240a9aed1",
    "time": [{
        "date": "2019-01-11T00:00:00.000Z",
        "duration": 480,
        "state": "DRAFT"
    }, {
        "date": "2019-01-11T00:00:00.000Z",
        "duration": 480,
        "state": "DRAFT"
    }
    // ...
}]

希望您可以看到durationpersonId分组了,但是我还无法弄清楚如何将另一个分组作为{如果time在给定日期具有多个date,则{1}}是重复的。

是否可以按ID进行分组,推送到一个数组,然后将该数组中的值分组为一个聚合,还是我的应用程序需要映射/减少结果呢?

2 个答案:

答案 0 :(得分:1)

我建议连续运行两个$group操作:

db.time.aggregate({
  // first, group all entries by personId and date
  $group: {
    _id: {
      personId: "$personId",
      date: "$date"
    },
    entries: {
      $push: {
        groupId: "$groupId",
        duration: "$duration",
        state: "$state"
      }
    }
  }
}, {
  // then, group previously aggregated entries by personId
  $group: {
    _id: "$_id.personId",
    time: {
      $push: {
        date: "$_id.date",
        entries: "$entries"
      }
    }
  }
}, {
  // finally, rename _id to personId
  $project: {
    _id: 0,
    personId: "$_id",
    time: "$time"
  }
})

在猫鼬中应该是这样的:

Time.aggregate()
  .match({
    date: {
      $gte: new Date(start),
      $lte: new Date(end)
    }
  })
  .group({
    _id: {
      personId: '$personId',
      date: '$date'
    },
    entries: {
      $push: {
        groupId: '$groupId',
        duration: '$duration',
        state: '$state'
      }
    }
  })
  .group({
    _id: '$_id.personId',
    time: {
      $push: {
        date: '$_id.date',
        entries: '$entries'
      }
    }
  })
  .project({
    _id: false,
    personId: '$_id',
    time: '$time'
  })

答案 1 :(得分:0)

db.getCollection("dummyCollection").aggregate(
[
    { 
        "$group" : {
            "_id" : "$personId", 
            "time" : {
                "$push" : {
                    "date" : "$date", 
                    "duration" : "$duration", 
                    "state" : "$state"
                }
            }
        }
    }, 
    { 
        "$project" : {
            "_id" : false, 
            "personId" : "$_id", 
            "time" : "$time"
        }
    }, 
    { 
        "$unwind" : "$time"
    }, 
    { 
        "$group" : {
            "_id" : "$time.date", 
            "time" : {
                "$addToSet" : "$time"
            }
        }
    }
]

);

  

使用$ addToSet返回所有唯一值的数组,这些值是通过将表达式应用于按键共享同一组文档的一组文档中的每个文档而得出的。