package com.mongodb.hvdf.rollup; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.hvdf.api.ConfigurationError; import com.mongodb.hvdf.api.ServiceException; import com.mongodb.hvdf.configuration.PluginConfiguration; public class GroupCountRollup extends RollupOperation { protected final String fieldExtention; protected final List<RangeCounter> ranges; public GroupCountRollup(PluginConfiguration config){ this.fieldExtention = "." + "group_count"; // any field mentioned in the config is a target DBObject rawConfig = config.getRaw(); ranges = new ArrayList<RangeCounter>(rawConfig.keySet().size()); for(String fieldName : rawConfig.keySet()){ Object rangesObj = rawConfig.get(fieldName); if(rangesObj instanceof BasicDBList){ ranges.add(new RangeCounter(fieldName, (BasicDBList)rangesObj)); } else { // the field must specify a range of values throw new ServiceException("Expected a list of range values", ConfigurationError.INVALID_CONFIG_TYPE). set("configuring", GroupCountRollup.class). set("field", fieldName); } } } @Override public DBObject getUpdateClause(DBObject sample) { BasicDBObject incFields = new BasicDBObject(); for(RangeCounter counter : ranges){ Object valueObj = getNestedFieldValue(counter.getFieldName(), sample); if(valueObj != null){ if (valueObj instanceof DBObject){ // this might be a nested *do everything* request // TODO : handle recursing into the object adding all fields } else { // this is the normal case, we can apply it directly as a clause incFields.append(counter.getIncField(valueObj), 1); } } } if(incFields.size() > 0){ return new BasicDBObject("$inc", incFields); } else { return new BasicDBObject(); } } } class RangeCounter{ private static Logger logger = LoggerFactory.getLogger(RangeCounter.class); private final String fieldName; private final String fieldNamePrefix; private final TreeSet<Object> rangesValues; public RangeCounter(String fieldName, BasicDBList rangesObj) { this.fieldName = fieldName; this.fieldNamePrefix = fieldName + ".group_count."; this.rangesValues = new TreeSet<Object>(); this.rangesValues.addAll(rangesObj); } public String getFieldName() { return this.fieldName; } public String getIncField(Object value){ if(value != null){ try{ Object floor = rangesValues.floor(value); if(floor != null){ return this.fieldNamePrefix + floor.toString(); } } catch(Exception e) { logger.warn("Value {} for field {} not compatible with ranges", value, this.fieldNamePrefix); } } // Doesnt fit any range, its in the low category return this.fieldNamePrefix + "low"; } }