【问题标题】:Multiple Counts with single query in mongodbmongodb中单个查询的多个计数
【发布时间】:2019-02-04 21:43:24
【问题描述】:

我是 Mongo Db 的新手,希望能在此查询方面提供一些帮助。在过去的几天里,我一直在这里筛选帖子,撕扯头发,看看是否能找到与我的查询相关的任何内容,但没有运气。

我有一个包含与以下结构类似的文档的集合:

_id: xyz
Movieid: 123
MovieName: Titanic
ReleaseDate: 2000-01-01

_id: uvw
Movieid: 456
MovieName: Titanic II
ReleaseDate: 2018-01-01

_id: pqr
Movieid: 789
MovieName: Titanic III
ReleaseDate: 

我希望在以下 3 个单独的列中将输出作为总电影数、具有发行日期的电影和没有发行日期的电影的计数:

Total   |   Released  |     UnReleased
 3      |       2     |          1

我能够编写单独的查询来执行计数,但我无法成功地将所有这些合并到一个查询中。最终目标是创建一个将这些计数作为输出的视图。我曾尝试使用 $and 等运算符,但似乎无法让查询按预期工作....这是我所得到的:

db.getCollection("Movies").aggregate({
  "$and": [
    { "$match": { "ReleaseDate": { "$exists": true } }},
    { "$count": "Total" },
    { "$match": { "ReleaseDate": { "$exists": true, "$nin": [""] } }},
    { "$count": "Released" },
    { "$match": { "ReleaseDate": { "$exists": true, "$in": [""] } }},
    { "$count": "Unreleased" }
  ]
})

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    你可以试试下面$facet聚合

    $count 聚合将始终为您提供仅单个匹配 ($match) 条件的计数。因此,您需要将每个计数进一步划分为多个部分,这就是 $facet 通过在同一组输入文档上的单个阶段内处理多个聚合管道所提供的。

    db.collection.aggregate([
      { "$facet": {
        "Total": [
          { "$match" : { "ReleaseDate": { "$exists": true }}},
          { "$count": "Total" },
        ],
        "Released": [
          { "$match" : {"ReleaseDate": { "$exists": true, "$nin": [""] }}},
          { "$count": "Released" }
        ],
        "Unreleased": [
          { "$match" : {"ReleaseDate": { "$exists": true, "$in": [""] }}},
          { "$count": "Unreleased" }
        ]
      }},
      { "$project": {
        "Total": { "$arrayElemAt": ["$Total.Total", 0] },
        "Released": { "$arrayElemAt": ["$Released.Released", 0] },
        "Unreleased": { "$arrayElemAt": ["$Unreleased.Unreleased", 0] }
      }}
    ])
    

    Output

    [{
        "Total": 3,
        "Released": 2,
        "Unreleased": 1
    }]
    

    【讨论】:

    • 非常感谢安东尼。这解决了我的问题。不知道 $facet 运算符。我只需要对上面的代码做一个小的改动。我用 db.collection.aggregate 替换了 db.collection.find 因为它给我一个错误,可能是因为 $facet 是一个聚合运算符?非常感谢您的帮助:)
    • @AnthonyWinzlet 我从 mongo Unrecognized pipeline stage name: '$facet'得到一个错误
    • @NithinChandran 你的 mongodb 版本是什么?因为$facet已经在mongodb 3.2及以上版本中引入了。
    • @AnthonyWinzlet 我的 mongodb 版本低于 3.4。同时我得到了它不工作的原因
    • @LiorMagen 回答您的第一个问题...如果您可以看到,我已在输出中发布了链接。您可以删除 $projectsee 会发生什么。 $facet 将为您提供每个管道计数的嵌套字段。对于第二个问题,我将编辑我的答案。
    【解决方案2】:
    db.Movies.aggregate(
    
        // Pipeline
        [
            // Stage 1
            {
                $group: {
                    _id: null,
                    Total: {
                        $sum: 1
                    },
                    docs: {
                        $push: '$$ROOT'
                    }
                }
            },
    
            // Stage 2
            {
                $project: {
                    _id: 0,
                    Total: 1,
                    Released: {
                        $filter: {
                            input: "$docs",
                            as: "doc",
                            cond: {
                                $ne: ["$$doc.ReleaseDate", ""]
                            }
                        }
                    },
                    Unreleased: {
                        $filter: {
                            input: "$docs",
                            as: "doc",
                            cond: {
                                $eq: ["$$doc.ReleaseDate", ""]
                            }
                        }
                    },
                }
            },
    
            // Stage 3
            {
                $project: {
                    Total: 1,
                    Released: {
                        $size: '$Released'
                    },
                    UnReleased: {
                        $size: '$Unreleased'
                    }
                }
            },
    
        ]
    
    
    
    );
    

    【讨论】:

    • 谢谢你,它帮助了我。问题,您将如何返回文档数据?
    【解决方案3】:

    您可以使用以下聚合。

    $gt > null - 检查聚合表达式中是否存在字段。

    $cond$sum 根据发布日期过滤器输出 0 和 1。

    $add 将已释放和未释放计数添加到输出总数中。

    db.Movies.aggregate([
     {"$group":{
       "_id":null,
       "Unreleased":{"$sum":{"$cond":[{"$and":[{"$gt":["$ReleaseDate",null]},{"$ne":["$ReleaseDate",""]}]},0,1]}},
       "Released":{"$sum":{"$cond":[{"$and":[{"$gt":["$ReleaseDate",null]},{"$ne":["$ReleaseDate",""]}]},1,0]}}
     }},
     {"$addFields":{"Total":{"$add":["$Unreleased","$Released"]}}}
    ])
    

    【讨论】:

    • 谢谢 Veeram。我尝试了上面的查询,但是我得到 0 作为 Unreleased 的输出计数。理想情况下,我们希望避免添加已发布和未发布来获得总数,因为我们可能有不属于这两种情况的文档。不过感谢您的努力。干杯。
    • 不客气。您可以在小组赛中为 Total 添加另一个条目。
    猜你喜欢
    • 1970-01-01
    • 2019-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2011-09-19
    • 2019-01-12
    • 2019-02-03
    • 2011-01-22
    相关资源
    最近更新 更多