MongoDB 聚合管道中的平方根

7

在MongoDB聚合管道中,有没有一种方法可以获取字段的平方根?我想做类似这样的操作:

db.collection.aggregate(
  { $group: _id: null, sum: { $sum: "$values" }}, 
  { $project: { answer: { $sqrt: "$sum" }}})

我知道 $sqrt 或任何其他幂运算符不存在,但在聚合管道中有没有一种方法可以完成这个操作?我知道可以在 map-reduce 中使用用户定义的函数来完成此操作,但是在聚合管道中是否可能实现?


5
就像你所说的,$sqrt运算符今天不存在。相关JIRA工单。但是,这个链接提供了一个解决方法。 - Anand Jayabalan
3个回答

1
正如@AnandJayabalan指出的那样,$sqrt 运算符将在MongoDB 3.2版本中发布,并具有以下语法:
{ $sqrt: <number> }

在您的示例中,这将是:


db.collection.aggregate([
  { $group: { _id: null, total: { $sum: "$values" }}}, 
  { $project: { answer: { $sqrt: "$total" }}}])

在撰写本文时,为了解决问题,John Page的关于聚合框架内计算平方根的博客文章使用算术原语通过牛顿迭代法计算平方根。


假设您想要找到正数N的平方根,为了解释这个算法是如何工作的,牛顿法涉及到做一个有根据的猜测,猜测一个数字A,当它被平方后,将会接近于等于N
例如,如果 N = 121,您可能会猜测 A = 10,因为 A² = 100,这是一个接近的猜测,但您可以做得更好。
这种方法使用的方程式是“牛顿求平方根方程”。

enter image description here


where


  • N 是一个正数,你想要找到它的平方根
  • 是平方根符号
  • 表示“大约等于…”
  • A 是你的猜测值

牛顿法允许您重复估计若干次以逼近一个精确数字(如果必要的话)。以约翰·佩奇的例子N = 29和您猜测的A = 5为例,您可以将这些值输入方程式和算法步骤中。

a. 从猜测 A = 5 开始


. 将 N 除以猜测值 (29/5 = 5.9)

c. 将其加入猜测中 (5.9 + 5 = 10.9)


d. 然后将该结果除以2 (10.9/2 = 5.45)


将其设置为新的猜测值A = 5.45,然后重复执行,从b.开始。
"5.45 5.38555 5.38516",保留HTML标记。
经过2次迭代后,答案为3.1623,逐渐接近平方根的精确值。
现在,使用聚合框架(来自John Page的博客文章)并将其应用于您的示例,聚合管道将是:
var groupPipeline = { $group: _id: null, total: { $sum: "$values" } },
    firstGuess = { 
        $project : { 
            n : "$total", r : { $literal : 5 } /* similar to step a) in the algorithm, the $literal operator sets r to the value 5 */
        } 
    },
    refineStep = { 
        $project : { 
            n: 1, r : { 
                $divide : [  /* step d) of the algorithm */
                    { 
                        $add : [ /* step c) of the algorithm */
                            { $divide : [ "$n", "$r"] },  /* step b) of the algorithm */
                            "$r" 
                        ]
                    },
                    2 
                ]
            }
        }
    };

/* Run the aggregation pipeline */
> db.collection.aggregate(groupPipeline, firstGuess, refineStep, refineStep, refineStep)

> { "_id" : ObjectId("538062103439ddd3764ff791"), "n" : 29, "r" : 5.385164807134505 }

0

Mongo 3.2将为聚合框架提供本地sqrt方法

如果参数解析为null值或引用缺失的字段,则$sqrt返回null。如果参数解析为NaN,则$sqrt返回NaN。

$sqrt在负数上出错。


0

这篇文章非常古老,但是我们需要编写自己的立方根实现来替换$pow(x,1/3)。原因是我们正在使用AWS DocumentDB来避免托管和管理自己的MongoDB数据库。然而,AWS Document DB 不支持任何版本的$sqrt$pow操作符。我也无法弄清楚为什么他们不支持它。

我们实现了两个版本,使用牛顿法和哈雷方法(因为后者收敛更快)。从技术上讲,它们也基于@chridram使用聚合框架的答案。您可以复制确切的命令以重现它:

启动一个Docker容器并执行mongosh

docker run -d -p 27017:27017 --name test-mongo mongo:latest
docker exec -it test-mongo mongosh

牛顿法:

use test
db.roots.insert({n:29})
firstguess = { $project : { n : 1, r : { $literal : 1}}}
refine = { $project : { n: 1, r : { $multiply: [{$divide: [1, 3]},{$add:[{$divide: ["$n", {$multiply: ["$r","$r"]}]},{$multiply:[2, "$r"]}]}]
}}}
db.roots.aggregate([firstguess,refine,refine,refine,refine,refine,refine,refine,refine])

海莉方法:

use test
db.roots.insert({n:29})
firstguess = { $project : { n : 1, r : { $literal : 1}}}
refine = { $project : { n: 1, r :
{
    $multiply: [
        "$r",
        {
            $divide: [
                {
                    $add: [
                        {$multiply: ["$r", "$r", "$r"]},
                        {$multiply: [2, "$n"]}
                    ]
                },
                {
                    $add: [
                        {$multiply: [2, "$r", "$r", "$r"]},
                        "$n"
                    ]
                }
            ]
        }
    ]
}}}
db.roots.aggregate([firstguess,refine,refine,refine,refine,refine,refine,refine,refine])

有关实际公式的更多详细信息,请参见https://en.wikipedia.org/wiki/Cube_root

进一步的改进可以使用$addFields而不是$project。 这样更容易阅读。 请参见https://www.mongodb.com/docs/manual/reference/operator/aggregation/addFields/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接