使用MongoDB聚合管道展开和汇总子子文档

时间:2014-08-04 05:18:12

标签: mongodb

这是我正在使用的基本abtract架构:

var activity = {
  _id: ObjectId,
  occurrences: [{
    _id: ObjectId,
    date: Date,
    followers: [ ObjectID ],
    attendances: [{
      answer: String   
    }]
  }]
}

示例文件:

var activity = {
  _id: '123',
  occurrences: [{
    _id: '111',
    followers: [
      '777',
      '888'
    ],
    attendances: [{
      answer: 'yes'
    }, {
      answer: 'no'
    }]  
  }, {
    _id: '222',
    followers: [
      '555',
      '666'
    ],
    attendances: [{
      answer: 'yes'
    }, {
      answer: 'yes'
    }]
  }]
}

使用聚合管道我想将其分解为单独的事件,每个事件包含其答案与字符串匹配的出勤次数(即"是")。我可以将事情分解为个别事件但是在进一步崩溃时遇到困难。结果正确显示每次出现的次数,但是追随者数量是完全错误的。我可能让事情变得更加复杂,我也需要:

这是我的非工作尝试:

this.aggregate({
    $unwind: '$occurences'
  }, {
    $group: {
      _id: '$occurences._id',
      attendances: {
        $first: "$occurences.attendances"
      },
      followers: {
        $first: "$occurences.followers"
      },
    }
  }, {
    $unwind: '$attendances'
  }, {
    $match: {
      "attendances.answer": {
        $ne: "no"
      }
    }
  }, {
    $group: {
      _id: '$_id',
      attendances: {
        $sum: 1
      },
      followers: {
        $sum: {
          $size: {
            $ifNull: ["$followers", []]
          }
        }
      }
    }
  }, {
    $project: {
      attendances: 1,
      followers: 1,
    }
  }
);

我想要这个结果:

[{ _id: 111, attendances: 1, followers: 2 },
 { _id: 222, attendances: 2, followers: 2 }]

2 个答案:

答案 0 :(得分:0)

通过使用$size运算符来获取关注者计数,您可以使查询更简单一些。您仍然需要展开考勤数组以过滤掉“否”答案,然后分组以获得考勤人数。

db.coll.aggregate([
{
    $unwind: "$occurrences"
}, 
{
    $project : { 
        _id : 1,
        occurrenceId : "$occurrences._id",
        followers: { $size: "$occurrences.followers" }, 
        attendances : "$occurrences.attendances"
    }
},
{
    $unwind: "$attendances"
}, 
{
    $match: {
      "attendances.answer": "yes"
    }
}, 
{
    $group: {
      _id: { id: "$_id", occurrenceId : "$occurrenceId"},
      followers : { $first : "$followers" },
      attendances: {
        $sum: 1
      }
    }
}]);

修改

我使用您的示例文档的结果是:

{"_id": { "id": "123", "occurrenceId": "222" }, "followers": 2, "attendances": 2}
{"_id": { "id": "123", "occurrenceId": "111" }, "followers": 2, "attendances": 1}

答案 1 :(得分:0)

好的想通了。跟随者计数错误,因为参与者的展开操作创建了多个条目,每个条目都有相同的关注者。而不是使用$ sum来添加它们,我需要使用$ avg。

this.aggregate({
    $unwind: '$occurences'
  }, {
    $group: {
      _id: '$occurences._id',
      attendances: {
        $first: "$occurences.attendances"
      },
      followers: {
        $first: "$occurences.followers"
      },
    }
  }, {
    $unwind: '$attendances'
  }, {
    $match: {
      "attendances.answer": {
        $ne: "no"
      }
    }
  }, {
    $group: {
      _id: '$_id',
      attendances: {
        $sum: 1
      },
      followers: {
        $avg: {
          $size: {
            $ifNull: ["$followers", []]
          }
        }
      }
    }
  }
);