【问题标题】:Alternate for $size in aggregate after doing $unwind执行 $unwind 后,总计替换 $size
【发布时间】:2019-12-06 21:51:45
【问题描述】:

使用聚合生成管道。在我的聚合操作中,对另一个集合执行 $lookup,导致结果集合出现 16mb BSON 限制错误。搜索问题后发现 $unwind 会将数据展开到单独的行中,这很好,现在我想计算展开列表中的元素数。如果它是一个列表,我会在其上使用 $size。 使用的 Mongodb 版本 - 3.4

我尝试进行计数,但它给出了总计数。我需要与尺寸完全相同的结果。

db.user.aggregate([
{'$match': {'dateAdded': {'$gte': ISODate("2013-10-09T00:11:00.130Z"),
            '$lt': ISODate("2019-10-09T00:11:00.130Z")}}},
{'$lookup': {'from': 'course',
             'localField': '_id',
             'foreignField': 'userId',
             'as': 'course'}},
{'$project': {"email": 1,
             "firstName": 1,
             "lastName": 1,
             "dateAdded": 1,
             "numberOfCourse": {"$size": "$course"}}}])

# will give me result like below
[* 1 */
{
    "_id" : JUUID("d97af13f-c800-4000-b4ef"),
    "lastName" : "abc1",
    "email" : "abc1@gma.com",
    "dateAdded" : ISODate("2015-10-09T00:11:00.130Z"),
    "firstName" : "abc1",
    "numberOfCourse" : 5
}

/* 2 */
{
    "_id" : JUUID("66ff26fd-eb04-4000-afdc"),
    "lastName" : "abc2",
    "email" : "abc2@gma.com",
    "dateAdded" : ISODate("2015-08-24T17:33:10.887Z"),
    "firstName" : "abc2",
    "numberOfCourse" : 20
}

/* 3 */
{
    "_id" : JUUID("1b1ac31f-ec22-4000-a1df"),
    "lastName" : "abc3",
    "email" : "abc3@gma.com",
    "dateAdded" : ISODate("2016-08-08T11:37:37.533Z"),
    "firstName" : "abc3",
    "numberOfCourse" : 30
}]

现在,如果课程数量超过 16mb,则上述方法将不起作用。请建议使用 $unwind 实现相同结果的正确方法。

【问题讨论】:

  • 我猜你已经达到了 mongoDB 文档的最大限制,你可以提供你的示例数据,这样我们就可以重构你的查询了..
  • 是的,它达到了我在问题中已经提到的 MongoDB 文档的最大限制。这就是为什么在搜索问题时按照建议使用 unwind 的原因。我是 mongo 的新手,现在想弄清楚如何获得相同的结果。
  • 我们有很多方法来计算文档的数量 $count 甚至在日期和 $sum 上做一个 $group 会相似,所以每个课程文档都有一个列表或一个 userId ?当我要求您从您的两个集合中获取示例文档时,我认为您不理解,如果您可以提供我们可以检查的那些,那就很简单了。
  • 例如说用户集合是 [{user_id: xxx1}, {user_id:xxx2}, {user_id:xxx3}] 并且课程集合看起来像 [{course_id: cs1, user_id:xxx1}, {course_id: cs2, user_id:xxx1}, {course_id: cs3, user_id:xxx2}]

标签: mongodb aggregation-framework


【解决方案1】:

您可以使用嵌套管道,当然可以直接获取计数

试试这个

db.user.aggregate([
    {
        "$match": {
            "dateAdded": {
                "$gte": ISODate("2013-10-09T00:11:00.130Z"),
                "$lt": ISODate("2019-10-09T00:11:00.130Z")
            }
        }
    },
    {
        "$lookup": {
            "from": "course",
            "let": {
                "$userId": "$_id"
            },
            "pipeline": [
                {
                    "$match": {
                        "$expr": { "$eq": ["$$userId","$userId" ] }
                    }
                },
                {
                    "$count": "numberOfCourse"
                }
            ],
            "as": "course"
        }
    },
    {
        "$project": {
            "email": 1,
            "firstName": 1,
            "lastName": 1,
            "dateAdded": 1,
            "numberOfCourse": { "$arrayElemAt": ["$course.numberOfCourse",  0 ] }
        }
    }
])

【讨论】:

  • 谢谢,但我使用的是 mongodb 3.4。
  • 你在用猫鼬吗?如果是,请尝试使用填充,否则我将 mongodb 更新到 3.6
  • 不能轻易升级生产系统。
  • 如果您使用的是猫鼬,请使用填充mongoosejs.com/docs/populate.html
  • 谢谢,但我没有使用 mongoosejs
【解决方案2】:

正如你所说,你已经查询工作并添加了 $unwind,然后试试这个:

db.user.aggregate([
    {
        '$match': {
            'dateAdded': {
                '$gte': ISODate("2013-10-09T00:11:00.130Z"),
                '$lt': ISODate("2019-10-09T00:11:00.130Z")
            }
        }
    },
    {
        '$lookup': {
            'from': 'course',
            'localField': '_id',
            'foreignField': 'userId',
            'as': 'course'
        }
    }, { '$unwind': '$course' },
    { '$group': { _id: '$_id', count: { $sum: 1 }, "docs": { "$first": "$$ROOT" } } }, { '$addFields': { 'docs.numberOfCourse': "$count" } },
    { '$replaceRoot': { 'newRoot': "$docs" } },
    {
        '$project': {
            "email": 1,
            "firstName": 1,
            "lastName": 1,
            "dateAdded": 1,
            "numberOfCourse": 1
        }
    }]) 

在这里,我们在展开后按用户的 _id 进行分组,因为我们已经计算了只是在组中添加第一个文档而不是全部,以便克服相同的问题并在通过 "docs": { "$first": "$$ROOT" } 和作为组使用后保留原始文档原始文档包含在 docs 中,使用 $replaceRoot 将其带到顶层。

【讨论】:

  • mergeObjects 是一个问题,它在 3.4 中不可用。我得到了你的解决方案的计数,但没有得到所有的字段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多