在$ group聚合中使用$ regex $ reduce,以便显示长度

时间:2018-01-02 19:48:29

标签: mongodb mongodb-query aggregation-framework

我想我在这里有一个非常复杂的 - 不确定我是否可以这样做。

我的数据包含地址和数据字段。数据字段是十六进制值。我想运行一个聚合,按地址分组数据,然后是十六进制数据的长度。所有数据都将以16个字符长的形式出现,但该数据的长度应以字节为单位计算。

我想我必须取数据,去掉尾随的00(使用正则表达式00 + $),并将该数字除以2得到长度。之后,我将不得不按地址和最终字节长度进行分组。

示例数据集将是:

{addr:829, data:'4100004822000000'}
{addr:829, data:'4100004813000000'}
{addr:829, data:'4100004804000000'}
{addr:506, data:'0000108000000005'}
{addr:506, data:'0000108000000032'}
{addr:229, data:'0065005500000000'}

我想要的输出是:

{addr:829, length:5}
{addr:506, length:8}
{addr:229, length:4}

在聚合查询中甚至可以使用外部代码吗?

1 个答案:

答案 0 :(得分:3)

如果你的"数据"这不是太复杂。实际上是您在示例数据中显示的字符串。假设数据存在并设置为某些东西(您可以根据需要添加错误检查),您可以得到您想要的结果:

db.coll.aggregate([
    {$addFields:{lastNonZero:{$add:[2,{$reduce:{
        initialValue:-2,
        input:{$range:[0,{$strLenCP:"$data"},2]},
        in:{$cond:{
            if: {$eq:["00",{$substr:["$data","$$this",2]}]},
            then: "$$value",
            else: "$$this"
        }}
    }}]}}},
    {$group:{_id:{
        addr:"$addr", 
        length:{$divide:["$lastNonZero",2]}
    }}}
])

我使用了两个阶段,但如果您愿意,当然可以将它们合并为一个$group。在$reduce中,我一次单步执行data个2个字符,检查它们是否等于"00"。每次他们不是我更新值到我在序列中的位置。因为那将返回最后一个非" 00"对于字符,我们在其中添加2以查找到达结尾的零字符串开始的位置,然后在$ group中将它除以2以获得真实长度。

在您的示例数据上,返回:

{ "_id" : { "addr" : 229, "length" : 4 } }
{ "_id" : { "addr" : 506, "length" : 8 } }
{ "_id" : { "addr" : 829, "length" : 5 } }

您可以添加$project阶段,将字段名称转换为您想要返回的字段名称。