$mod 仅支持数字类型,不支持 MongoDb 中的 array 和 int

问题描述 投票:0回答:2

我的收藏中有这个文档结构:

{
  "grades": [
        { "grade": "A", "score": 8 },
        {"grade": "A", "score": 7 }
    ]
}

我需要过滤那些文档,当它们的

score
除以 7 时有 0 作为提醒。原始问题在here提出(问题 30)。他们的解决方案很简单:

db.restaurants.find(
                  {"grades.score" :
                     {$mod : [7,0]}
                  },
                     {"restaurant_id" : 1,"name":1,"grades":1}
                );

但是,为了练习,我想采用自己的解决方案,但行不通。

db.restaurants.aggregate([
    {
        "$match": {
           "$expr": {"$in": [0,   [ { $mod: [ "$grades.score", 7 ] }    ]  ]}
        }
    },
])

错误是:

PlanExecutor error during aggregation :: caused by :: $mod only supports numeric types, not array and int

基本上我想检查 0 是否在自定义数组中,该数组在模运算后仅包含单个值,如用于聚合时 $in文档中所述。

有没有办法让

$mod
作为聚合的一部分工作?

我看到类似的问题被问到here,但它仅引用成绩数组中的第一个分数,而不是全部。因此,就我而言,我应该看到开头给出的示例文档,因为

7 % 7 = 0

mongodb mongodb-query
2个回答
1
投票

使用

$map
函数将数组的每个值映射到模结果,然后检查结果数组中是否有 0。

您可以使用其中之一:

db.restaurants.aggregate([
  {
    $set: {
      mods: {
        "$map": {
          "input": "$grades.score",
          "as": "score",
          "in": {
            $mod: ["$$score", 7]
          }
        }
      }
    }
  },
  {
    "$match": {
      "$expr": {
        "$in": [0, "$mods"]
      }
    }
  }
])

蒙戈游乐场

如果您希望将其作为管道中的单个阶段:

db.restaurants.aggregate([
  {
    "$match": {
      "$expr": {
        "$in": [
          0,
          {
            "$map": {
              "input": "$grades.score",
              "as": "score",
              "in": {
                $mod: ["$$score", 7]
              }
            }
          }
        ]
      }
    }
  }
])

蒙戈游乐场


0
投票

这是

$reduce
的替代方案,当找到
0
模时,它可能会跳过一些计算,但仍然会迭代整个数组。在这种情况下,由于模计算非常有效,因此它不太可能真正带来任何真正的好处,除非您有非常非常很长的成绩列表。

用于比较的初始值是 $maxKey,它始终大于 任何其他值。只要您的列表不为空就可以。

db.restaurants.aggregate([
  {
    $set: {
      min_modulo: {
        $reduce: {
          input: "$grades.score",
          initialValue: { "$maxKey": 1 },
          in: {
            $cond: {
              if: { $eq: [ "$$value", 0] },
              // in theory, once we have a 0
              // don't calculate mods or the minimums any more
              then: "$$value",
              else: { $min: [{ $mod: ["$$this", 7] }, "$$value"] }
            }
          }
        }
      }
    }
  },
  { $match: { min_modulo: 0 } }
])

Mongo Playground 包含更多示例数据

© www.soinside.com 2019 - 2024. All rights reserved.