【问题标题】:MongoDB: $mod operator in aggregation pipelineMongoDB:聚合管道中的 $mod 运算符
【发布时间】:2016-09-11 11:38:36
【问题描述】:

我有一个包含 3772 个文档的 restaurants 集合,我正在尝试使用聚合框架计算在 grades 数组的第一个元素中包含 score 的文档总数,该数组是 7 的倍数。

查询:

db.restaurants.aggregate([
{$project: {remainder: {$mod: ["$grades.0.score", 7]},
            restaurant_id: 1,
            name: 1,
            grades: 1
            }
},
{$match: {remainder: {$eq: 0}}},
{$group: {_id: null, total: {$sum: 1}}}
])

但是,我收到一条错误消息,原因是在 $project 管道阶段使用了 $mod 运算符。错误信息如下:

$mod 只支持数值类型,不支持 Array 和 NumberDouble

但是,$grades.0.score7 都是整数,对吧?我应该进行哪些更改才能使此查询按预期工作?

示例文档:

{
"_id" : ObjectId("57290430139a4a37132c9e93"),
"address" : {
    "building" : "469",
    "coord" : [
        -73.961704,
        40.662942
    ],
    "street" : "Flatbush Avenue",
    "zipcode" : "11225"
},
"borough" : "Brooklyn",
"cuisine" : "Hamburgers",
"grades" : [
    {
        "date" : ISODate("2014-12-30T00:00:00Z"),
        "grade" : "A",
        "score" : 8
    },
    {
        "date" : ISODate("2014-07-01T00:00:00Z"),
        "grade" : "B",
        "score" : 23
    },
    {
        "date" : ISODate("2013-04-30T00:00:00Z"),
        "grade" : "A",
        "score" : 12
    },
],
"name" : "Wendy'S",
"restaurant_id" : "30112340"
}

【问题讨论】:

  • 您是否需要$mod 仅用于“等级”数组中的第一个元素?你能显示预期的输出吗?
  • 一直是"remainder": { "$mod": [ { "$arrayElemAt": [ "$grades.score", 0 ] }, 7 ] }。见$arrayElemAt。投射只会在以后的$group 中丢弃的字段也没有任何意义。并且表达式应该是$redact,而不是$project,然后是$match。效率更高。

标签: mongodb mongodb-query aggregation-framework nosql


【解决方案1】:

而不是$grades.0.score
$grades[0].score 在您的查询中。

以上是错误的。请参阅下面的正确形式。由于您要按第一个分数是 7 的倍数的成绩进行过滤,因此您应该像这样开始聚合。

db.restaurants.aggregate([{$match: {"grades.0.score": {$mod: [7, 0]}}},{$group: {_id: null, total: {$sum: 1}}}])

我将grade.0.score 更改为7 并运行命令检查它是否正常工作,它似乎按照你的意愿工作。

> db.restaurants.find().pretty();
{
        "_id" : 0,
        "address" : {
                "building" : "469",
                "coord" : [
                        -73.961704,
                        40.662942
                ],
                "street" : "Flatbush Avenue",
                "zipcode" : "11225"
        },
        "borough" : "Brooklyn",
        "cuisine" : "Hamburgers",
        "grades" : [
                {
                        "date" : ISODate("2014-12-30T00:00:00Z"),
                        "grade" : "A",
                        "score" : 7
                },
                {
                        "date" : ISODate("2014-07-01T00:00:00Z"),
                        "grade" : "B",
                        "score" : 23
                },
                {
                        "date" : ISODate("2013-04-30T00:00:00Z"),
                        "grade" : "A",
                        "score" : 12
                }
        ],
        "name" : "Wendy'S",
        "restaurant_id" : "30112340"

> db.restaurants.aggregate([{$match: {"grades.0.score": {$mod: [7, 0]}}},{$group:{_id:null,count:{$sum:1}}} ])    
{ "_id" : null, "count" : 1 }

【讨论】:

  • 试过了,所有文档的remainder 的值似乎都是null
  • @Calculus5000 如果您确实需要帮助,您应该考虑编辑您的问题并添加其他信息。 See my comment above
  • 请停止发布图片。您应该考虑复制/粘贴您的代码。
  • @user3100115 谢谢,我做到了,起初我发现把所有代码放在一起很麻烦,但现在我想我明白了。
【解决方案2】:

首先:为什么它不起作用?试试:

    db.restaurants.aggregate([
    {$project: {
        score0: "$grades.0.score",
        restaurant_id: 1,
        name: 1
        }
    }
    ])

您会看到 score0 返回 [0 个元素],因此它会输出一个数组,因此会出现错误消息。

基于另一个问题Get first element in array and return using Aggregate? (Mongodb),这里是您的问题的解决方案:

    db.restaurants.aggregate([
       {$unwind: "$grades"},
       {$group:{"_id":"$_id","grade0":{$first:"$grades"}}},
       {$project: {
          remainder: {$mod: ["$grade0.score", 7]},
          restaurant_id: 1,
          name: 1,
          grade0: 1,
          }
      },
      {$match: {remainder: {$eq: 0}}},
      {$group: {_id: null, total: {$sum: 1}}}
    ])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-11
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    相关资源
    最近更新 更多