Mapreducing计算可能存在或可能不存在的字段的出现次数

时间:2011-06-01 16:27:03

标签: javascript ruby-on-rails ruby mongodb mapreduce

这给了我一个错误{“断言”=>“地图调用失败:JS错误:ReferenceError:foo未定义nofile_b:4”。有什么想法吗?

class ObjResults
  include Mongoid::Document

field :foo, :type => Boolean, :default => false 
field :bar, :type => Boolean, :default => false 

def self.stats_by_user_id user_id
 map = <<-MAP
 function() { 
    if (this.user_id == "#{user_id}") {   
        hsh = {}    
        if (this.foo) {
            hsh["foo"] = this.foo
            }
        if (this.bar) {
            hsh["bar"] = this.bar
        }
        emit(this.user_id, hsh);  
    }
} 
MAP 

3 个答案:

答案 0 :(得分:1)

在分配哈希值时,您需要将foo和bar放在引号中:

hsh["foo"] = this.foo;  // or hsh.foo = this.foo

您可以考虑将此问题标记为javascript,因为ruby部分很小。

答案 1 :(得分:0)

JavaScript看起来很好,但是MongoDB可能会添加额外的限制,导致奇怪的错误消息。我可以想到您可以尝试的两件事:使用hasOwnProperty查看foobar是否存在:

map = <<-MAP
 function() { 
    if (this.user_id == "#{user_id}") {   
        hsh = { };
        if (this.hasOwnProperty('foo')) {
            hsh["foo"] = this.foo;
        }
        if (this.hasOwnProperty('bar')) {
            hsh["bar"] = this.bar;
        }
        emit(this.user_id, hsh);  
    }
} 
MAP

或使用括号表示法访问this的属性:

map = <<-MAP
 function() { 
    if (this.user_id == "#{user_id}") {   
        hsh = { };
        if (typeof this['foo'] != 'undefined') {
            hsh["foo"] = this.foo;
        }
        if (typeof this['bar'] != 'undefined') {
            hsh["bar"] = this.bar;
        }
        emit(this.user_id, hsh);  
    }
} 
MAP

请注意,我已经收紧了这个中的逻辑,看看foobar是否存在,而不仅仅是检查它们的真实性。

答案 2 :(得分:0)

我试图重现你的问题。但是,就实践问题而言,我写下了运行良好的代码。我只是希望这仍然有用。

命令行:

2.0.0p0 :023 > Band.all.to_a.map(&:bar)
=> [false, false, true, false]
2.0.0p0 :024 > Band.all.to_a.map(&:foo)
=> [false, false, true, true]
2.0.0p0 :025 > Band.mar.to_a
=> [{"_id"=>"Apple", "value"=>{"likes"=>888.0, "hh"=>3.0}}, {"_id"=>"IBM", "value"=>{"likes"=>1431.0, "hh"=>0.0}}]

代码结构:

class Band
  include Mongoid::Document
  field :name, type: String
  field :likes, type: Integer, default: 0
  field :foo, type: Boolean, default: false
  field :bar, type: Boolean, default: false

  def self.mar
    map = %Q{
      function() {
        hsh = {};
        if(this.foo) {hsh.foo = this.foo}
        if(this.bar) {hsh.bar = this.bar}
        emit(this.name, { likes: this.likes, hh: hsh });
      }
    }

    reduce = %Q{
      function(key, values) {
        var result = { likes: 0, hh: 0 };
        values.forEach(function(value) {
          result.likes += value.likes;
          if(value.hh.foo) {result.hh += 1}
          if(value.hh.bar) {result.hh += 1}

        });
        return result;
      }
    }

    self.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: true)
  end
end