【问题标题】:Generating a Structure for Aggregation生成聚合结构
【发布时间】:2017-06-26 18:30:34
【问题描述】:

所以这里有一个问题。我想做的是给定一组输入值生成一个数据结构。

由于这是多语言提交,让我们将输入列表视为键/值对数组。因此,哈希、映射、字典或任何漂浮在你船上的术语的数组。我将这里的所有符号保留为 JSON,希望它足够通用,可以翻译/解码。

所以对于输入,假设我们有这个:

[ { "4": 10 }, { "7": 9 }, { "90": 7 }, { "1": 8 } ] 

可能有点多余,但让我们坚持下去。

所以从那个输入,我想得到这个结构。我给出了一个完整的结构,但 important 部分是 "weight" 下的值返回的内容:

[
   { "$project": {
       "user_id": 1,
       "content": 1,
       "date": 1,
       "weight": { "$cond": [
           { "$eq": ["$user_id": 4] },
           10,
           { "$cond": [ 
               { "$eq": ["$user_id": 7] },
               9,
               { "$cond": [
                   { "$eq": ["$user_id": 90] },
                   7,
                   { "$cond": [
                       { "$eq": ["$user_id": 1] },
                       8, 
                       0
                   ]}
               ]}
           ]}
       ]}
   }}
]

因此,我正在寻找的解决方案通过使用 输入 来填充结构中“重量”的结构内容,如图所示。

是的,结构中看起来像数字的值必须是数字而不是字符串,因此无论采用何种语言实现,JSON 编码版本必须看起来完全相同。

或者,给我一个更好的方法来获得相同的结果,即根据匹配的user_id 分配 权重 值。

有没有人有办法解决这个问题?

对任何语言实现都会感到满意,因为我认为看看如何创建结构是公平的。

我会尝试添加自己,但要感谢良好的实现。

编码愉快。

【问题讨论】:

  • 哦,如果您投了反对票或未投赞成票,请给出合理的解释。现实情况是这样的结构需要生成,所以如果您不理解,请提出问题或继续前进。我的政策是自己解释,以便内容可以更改或根本不做任何事情。即使你不明白,其他人也可能明白这一点。

标签: mongodb aggregation-framework


【解决方案1】:

当我有时间考虑这个问题时,我跑回了 perl 并解决了这个问题:

use Modern::Perl;

use Moose::Autobox;
use JSON;

my $encoder = JSON->new->pretty;

my $input = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7 }, { 1 => 8 } ];

my $stack = [];

foreach my $item ( reverse @{$input} ) {

  while ( my ( $key, $value ) = each %{$item} ) {
    my $rec = {
      '$cond' => [
        { '$eq' => [ '$user_id', int($key) ] },
        $value
      ]
    };

    if ( $stack->length == 0 ) {
      $rec->{'$cond'}->push( 0 );
    } else {
      my $last = $stack->pop;
      $rec->{'$cond'}->push( $last );
    }

    $stack->push( $rec );
  }

}

say $encoder->encode( $stack->[0] );

所以这个过程非常简单。

  1. 遍历数组中的每一项,获取条目的键和值

  2. 创建一个新的“文档”,其中包含“$cond”键的数组参数,其中只有所需的三个条目中的两个。这些是分配用于测试“$user_id”和返回的“权重”值的值。

  3. 测试 stack 的外部变量的长度,如果它是空的(第一次通过)然后 push0 的值,如图所示在文档中最后一个嵌套元素到“$cond”键的末尾。

  4. 如果已经存在某些内容(长度 > 0),则将该值作为文档“$cond”键中的第三个值推送

  5. 将该文档作为 stack 的值放回原处,然后重复下一项

因此,清单中有一些事情,例如颠倒输入的顺序,这不是必需的,但会在嵌套输出中产生自然顺序。此外,我选择的外部“堆栈”是一个数组,因为测试运算符看起来很简单。但它实际上只是一个不断重复使用、扩充和替换的奇异值。

JSON 打印也只是用来显示输出。真正想要的只是将 stack 的结果值合并到结构中。

然后我将逻辑转换为 ruby​​,就像 OP 使用的语言一样,我从中获得了如何生成这种嵌套结构的灵感:

require 'json'

input = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7 }, { 1 => 8 } ]

stack = []

input.reverse_each {|item|

  item.each {|key,value|
    rec = {
      '$cond' => [
        { '$eq' => [ '$user_id', key ] },
        value
      ]
    }

    if ( stack.length == 0 )
      rec['$cond'].push( 0 )
    else
      last = stack.pop
      rec['$cond'].push( last )
    end

    stack.push( rec )
  }

}

puts JSON.pretty_generate(stack[0])

然后最终进入最终形式以生成 OP 想要的管道:

require 'json'

userWeights = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7}, { 1 => 8 } ]

stack = []

userWeights.reverse_each {|item|

  item.each {|key,value|
    rec = {
      '$cond' => [
        { '$eq' => [ '$user_id', key ] },
        value
      ]
    }

    if ( stack.length == 0 )
      rec['$cond'].push( 0 )
    else
      last = stack.pop
      rec['$cond'].push( last )
    end

    stack.push( rec )
  }

}

pipeline = [
    { '$project' => {
        'user_id' => 1,
        'content' => 1,
        'date' => 1,
        'weight' => stack[0]
    }},
    { '$sort' => { 'weight' => -1, 'date' => -1 } }
]

puts JSON.pretty_generate( pipeline )

因此,这是一种生成要传递给聚合的结构的方法,以便应用特定于 user_id 的“权重”并对集合中的结果进行排序。

【讨论】:

    【解决方案2】:

    首先感谢 Neil 对 here 的帮助,这项锻炼对我来说非常棒,而且速度非常快。对于那些使用 mongoid 的人,这是我用来创建 weight 参数的,其中Recommended_user_ids 是一个数组:

        def self.project_recommended_weight recommended_user_ids
          return {} unless recommended_user_ids.present?
          {:weight => create_weight_statement(recommended_user_ids.reverse)}
        end
    
        def self.create_weight_statement recommended_user_ids, index=0
          return 0 if index == recommended_user_ids.count
          {"$cond" => [{ "$eq" => ["$user_id", recommended_user_ids[index]] },index+1,create_weight_statement(recommended_user_ids,index+1)]}
        end
    

    所以要将它添加到管道中,只需像这样合并哈希:

    {"$project" => {:id => 1,:posted_at => 1}.merge(project_recommended_weight(options[:recommended_user_ids]))}
    

    【讨论】:

      猜你喜欢
      • 2021-07-26
      • 2012-05-18
      • 2019-10-05
      • 2020-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多