Permalink
Browse files

did group_by functionality, version bump

  • Loading branch information...
s12chung committed Sep 1, 2012
1 parent 4d8265e commit b6ab59180093de68c9fdd6253f079d7390ba282a
View
@@ -12,3 +12,4 @@ tmtags
\#*
.\#*
*.swp
+.idea/*
View
@@ -1 +1 @@
-0.8.1
+0.8.2
@@ -1,13 +1,17 @@
module Mongoid::TaggableWithContext::AggregationStrategy
module RealTime
extend ActiveSupport::Concern
-
+
included do
set_callback :save, :after, :update_tags_aggregations_on_save
set_callback :destroy, :after, :update_tags_aggregations_on_destroy
end
module ClassMethods
+ def tag_name_attribute
+ "_id"
+ end
+
# Collection name for storing results of tag count aggregation
def aggregation_database_collection_for(context)
@@ -17,15 +21,15 @@ def aggregation_database_collection_for(context)
def aggregation_collection_for(context)
"#{collection_name}_#{context}_aggregation"
end
-
+
def tags_for(context, conditions={})
- aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(_id: 1).to_a.map{ |t| t["_id"] }
+ aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(tag_name_attribute.to_sym => 1).to_a.map{ |t| t[tag_name_attribute] }
end
# retrieve the list of tag with weight(count), this is useful for
# creating tag clouds
def tags_with_weight_for(context, conditions={})
- aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(_id: 1).to_a.map{ |t| [t["_id"], t["value"].to_i] }
+ aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(tag_name_attribute.to_sym => 1).to_a.map{ |t| [t[tag_name_attribute], t["value"].to_i] }
end
def recalculate_all_context_tag_weights!
@@ -58,14 +62,18 @@ def recalculate_tag_weights!(context)
# adapted from https://github.com/jesuisbonbon/mongoid_taggable/commit/42feddd24dedd66b2b6776f9694d1b5b8bf6903d
def tags_autocomplete(context, criteria, options={})
- result = aggregation_database_collection_for(context).find({:_id => /^#{criteria}/})
+ result = aggregation_database_collection_for(context).find({tag_name_attribute.to_sym => /^#{criteria}/})
result = result.sort(value: -1) if options[:sort_by_count] == true
result = result.limit(options[:max]) if options[:max] > 0
- result.to_a.map{ |r| [r["_id"], r["value"]] }
+ result.to_a.map{ |r| [r[tag_name_attribute], r["value"]] }
end
end
-
+
protected
+
+ def get_conditions(context, tag)
+ {self.class.tag_name_attribute.to_sym => tag}
+ end
def update_tags_aggregation(context_array_field, old_tags=[], new_tags=[])
context = context_array_to_context_hash[context_array_field]
@@ -79,10 +87,10 @@ def update_tags_aggregation(context_array_field, old_tags=[], new_tags=[])
tags_removed.each do |tag|
- coll.find({_id: tag}).upsert({'$inc' => {:value => -1}})
+ coll.find(get_conditions(context, tag)).upsert({'$inc' => {:value => -1}})
end
tags_added.each do |tag|
- coll.find({_id: tag}).upsert({'$inc' => {:value => 1}})
+ coll.find(get_conditions(context, tag)).upsert({'$inc' => {:value => 1}})
end
#coll.find({_id: {"$in" => tags_removed}}).update({'$inc' => {:value => -1}}, [:upsert])
#coll.find({_id: {"$in" => tags_added}}).update({'$inc' => {:value => 1}}, [:upsert])
@@ -0,0 +1,53 @@
+module Mongoid::TaggableWithContext::GroupBy::AggregationStrategy
+ module RealTime
+ extend ActiveSupport::Concern
+ include Mongoid::TaggableWithContext::GroupBy::TaggableWithContext
+ include Mongoid::TaggableWithContext::AggregationStrategy::RealTime
+
+ module ClassMethods
+ def tag_name_attribute
+ "name"
+ end
+
+ def tags_for(context, group_by, conditions={})
+ results = if group_by
+ query(context, group_by).to_a.map{ |t| t[tag_name_attribute] }
+ else
+ super(context, conditions)
+ end
+ results.uniq
+ end
+
+ def tags_with_weight_for(context, group_by, conditions={})
+ results = if group_by
+ query(context, group_by).to_a.map{ |t| [t[tag_name_attribute], t["value"].to_i] }
+ else
+ super(context, conditions)
+ end
+
+ tag_hash = {}
+ results.each do |tag, weight|
+ tag_hash[tag] ||= 0
+ tag_hash[tag] += weight
+ end
+ tag_hash.to_a
+ end
+
+ protected
+ def query(context, group_by)
+ aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }, :group_by => group_by}).sort(tag_name_attribute.to_sym => 1)
+ end
+ end
+
+ protected
+
+ def get_conditions(context, tag)
+ conditions = {:name => tag}
+ group_by_field = self.class.get_tag_group_by_field_for(context)
+ if group_by_field
+ conditions.merge!({:group_by => self.send(group_by_field)})
+ end
+ conditions
+ end
+ end
+end
@@ -0,0 +1,43 @@
+module Mongoid::TaggableWithContext::GroupBy
+ module TaggableWithContext
+ extend ActiveSupport::Concern
+ include Mongoid::TaggableWithContext
+
+ module ClassMethods
+ def taggable(*args)
+ super(*args)
+ args.extract_options!
+ tags_field = (args.blank? ? :tags : args.shift).to_sym
+ self.taggable_with_context_options[tags_field].reverse_merge!(:group_by_field => nil)
+
+ class_eval <<-END
+ class << self
+ def #{tags_field}(group_by=nil)
+ tags_for(:"#{tags_field}", group_by)
+ end
+
+ def #{tags_field}_with_weight(group_by=nil)
+ tags_with_weight_for(:"#{tags_field}", group_by)
+ end
+
+ def #{tags_field}_group_by_field
+ get_tag_group_by_field_for(:"#{tags_field}")
+ end
+ end
+ END
+ end
+
+ def tags_for(context, group_by, conditions={})
+ raise AggregationStrategyMissing
+ end
+
+ def tags_with_weight_for(context, group_by, conditions={})
+ raise AggregationStrategyMissing
+ end
+
+ def get_tag_group_by_field_for(context)
+ self.taggable_with_context_options[context][:group_by_field]
+ end
+ end
+ end
+end
@@ -2,4 +2,6 @@
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context')
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/map_reduce')
-require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/real_time')
+require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/real_time')
+require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/group_by/taggable_with_context')
+require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/group_by/aggregation_strategy/real_time')
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = "mongoid_taggable_with_context"
- s.version = "0.8.1.1"
+ s.version = "0.8.2"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Aaron Qian"]
- s.date = "2012-03-14"
+ s.date = "2012-09-01"
s.description = "It provides some helpers to create taggable documents with context."
s.email = "aq1018@gmail.com"
s.extra_rdoc_files = [
@@ -28,6 +28,8 @@ Gem::Specification.new do |s|
"lib/mongoid/taggable_with_context.rb",
"lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb",
"lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb",
+ "lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb",
+ "lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb",
"lib/mongoid_taggable_with_context.rb",
"mongoid_taggable_with_context.gemspec",
"spec/mongoid_taggable_with_context_spec.rb",
@@ -36,7 +38,7 @@ Gem::Specification.new do |s|
s.homepage = "http://github.com/aq1018/mongoid_taggable_with_context"
s.licenses = ["MIT"]
s.require_paths = ["lib"]
- s.rubygems_version = "1.8.10"
+ s.rubygems_version = "1.8.24"
s.summary = "Mongoid taggable behaviour"
s.test_files = [
"spec/mongoid_taggable_with_context_spec.rb",
@@ -47,22 +49,22 @@ Gem::Specification.new do |s|
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
- s.add_runtime_dependency(%q<mongoid>, [">= 3.0.1"])
+ s.add_runtime_dependency(%q<mongoid>, [">= 3.0.0"])
s.add_development_dependency(%q<database_cleaner>, [">= 0"])
s.add_development_dependency(%q<rspec>, [">= 0"])
s.add_development_dependency(%q<yard>, [">= 0"])
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
s.add_development_dependency(%q<jeweler>, [">= 0"])
else
- s.add_dependency(%q<mongoid>, [">= 3.0.1"])
+ s.add_dependency(%q<mongoid>, [">= 3.0.0"])
s.add_dependency(%q<database_cleaner>, [">= 0"])
s.add_dependency(%q<rspec>, [">= 0"])
s.add_dependency(%q<yard>, [">= 0"])
s.add_dependency(%q<bundler>, [">= 1.0.0"])
s.add_dependency(%q<jeweler>, [">= 0"])
end
else
- s.add_dependency(%q<mongoid>, ["3.0.1"])
+ s.add_dependency(%q<mongoid>, [">= 3.0.0"])
s.add_dependency(%q<database_cleaner>, [">= 0"])
s.add_dependency(%q<rspec>, [">= 0"])
s.add_dependency(%q<yard>, [">= 0"])
@@ -27,6 +27,15 @@ class M2
taggable :artists
end
+class M3
+ include Mongoid::Document
+ include Mongoid::TaggableWithContext::GroupBy::AggregationStrategy::RealTime
+
+ field :user
+ taggable :group_by_field => :user
+ taggable :artists, :group_by_field => :user
+end
+
describe Mongoid::TaggableWithContext do
context "default field value" do
@@ -162,9 +171,9 @@ class M2
context "retriving index" do
context "on create directly" do
before :each do
- klass.create!(:tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
- klass.create!(:tags => "juice food bee zip", :artists => "grant andrew andy")
- klass.create!(:tags => "honey strip food", :artists => "mandy aaron andy")
+ klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
+ klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
+ klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
end
it "should retrieve the list of all saved tags distinct and ordered" do
@@ -243,9 +252,9 @@ class M2
context "on create then update" do
before :each do
- m1 = klass.create!(:tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
- m2 = klass.create!(:tags => "juice food bee zip", :artists => "grant andrew andy")
- m3 = klass.create!(:tags => "honey strip food", :artists => "mandy aaron andy")
+ m1 = klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
+ m2 = klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
+ m3 = klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
m1.tags_array = m1.tags_array + %w[honey strip shoe]
m1.save!
@@ -286,9 +295,9 @@ class M2
context "on create, update, then destroy" do
before :each do
- m1 = klass.create!(:tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
- m2 = klass.create!(:tags => "juice food bee zip", :artists => "grant andrew andy")
- m3 = klass.create!(:tags => "honey strip food", :artists => "mandy aaron andy")
+ m1 = klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
+ m2 = klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
+ m3 = klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
m1.tags_array = m1.tags_array + %w[honey strip shoe] - %w[food]
m1.save!
@@ -353,4 +362,65 @@ class M2
klass.aggregation_collection_for(:artists).should == "m2s_artists_aggregation"
end
end
+
+ context "realtime aggregation group by" do
+ let(:klass) { M3 }
+ it_should_behave_like "aggregation"
+
+ it "should generate the tags aggregation collection name correctly" do
+ klass.aggregation_collection_for(:tags).should == "m3s_tags_aggregation"
+ end
+
+ it "should generate the artists aggregation collection name correctly" do
+ klass.aggregation_collection_for(:artists).should == "m3s_artists_aggregation"
+ end
+
+ context "for groupings" do
+ before :each do
+ klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
+ klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
+ klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
+ end
+
+ it "should retrieve the list of all saved tags distinct and ordered" do
+ klass.tags("user1").should == %w[ant bee food juice zip]
+ klass.tags("user2").should == %w[food honey strip]
+
+ klass.artists("user1").should == %w[aaron andrew andy grant greg jeff mandy]
+ klass.artists("user2").should == %w[aaron andy mandy]
+ end
+
+ it "should retrieve a list of tags with weight" do
+ klass.tags_with_weight("user1").should == [
+ ['ant', 1],
+ ['bee', 2],
+ ['food', 2],
+ ['juice', 1],
+ ['zip', 1]
+ ]
+
+ klass.tags_with_weight("user2").should == [
+ ['food', 1],
+ ['honey', 1],
+ ['strip', 1]
+ ]
+
+ klass.artists_with_weight("user1").should == [
+ ['aaron', 1],
+ ['andrew', 1],
+ ['andy', 2],
+ ['grant', 1],
+ ['greg', 1],
+ ['jeff', 1],
+ ['mandy', 1]
+ ]
+
+ klass.artists_with_weight("user2").should == [
+ ['aaron', 1],
+ ['andy', 1],
+ ['mandy', 1]
+ ]
+ end
+ end
+ end
end

0 comments on commit b6ab591

Please sign in to comment.