/*
* Copyright (c) www.bugull.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.tooan.ynpay.third.mongodb;
import com.mongodb.*;
import com.mongodb.MapReduceCommand.OutputType;
import net.tooan.ynpay.third.jfinal.log.Logger;
import net.tooan.ynpay.third.mongodb.exception.MapReduceException;
import net.tooan.ynpay.third.mongodb.mapper.MapperUtil;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Aggregation and MapReduce.
*
* @author Frank Wen(xbwen@hotmail.com)
*/
public class AdvancedDao<T> extends BuguDao<T> {
private final static Logger logger = Logger.getLogger(AdvancedDao.class);
public AdvancedDao(Class<T> clazz) {
super(clazz);
}
public double max(String key) {
return max(key, new BasicDBObject());
}
public double max(String key, BuguQuery query) {
return max(key, query.getCondition());
}
private double max(String key, DBObject query) {
if (!this.exists(query)) {
return 0;
}
StringBuilder map = new StringBuilder("function(){emit('");
map.append(key);
map.append("', {'value':this.");
map.append(key);
map.append("});}");
String reduce = "function(key, values){var max=values[0].value; for(var i=1;i<values.length; i++){if(values[i].value>max){max=values[i].value;}} return {'value':max}}";
Iterable<DBObject> results = null;
try {
results = mapReduce(map.toString(), reduce, query);
} catch (MapReduceException ex) {
logger.error(ex.getMessage(), ex);
}
DBObject result = results.iterator().next();
DBObject dbo = (DBObject) result.get("value");
return Double.parseDouble(dbo.get("value").toString());
}
public double min(String key) {
return min(key, new BasicDBObject());
}
public double min(String key, BuguQuery query) {
return min(key, query.getCondition());
}
private double min(String key, DBObject query) {
if (!this.exists(query)) {
return 0;
}
StringBuilder map = new StringBuilder("function(){emit('");
map.append(key);
map.append("', {'value':this.");
map.append(key);
map.append("});}");
String reduce = "function(key, values){var min=values[0].value; for(var i=1;i<values.length; i++){if(values[i].value<min){min=values[i].value;}} return {'value':min}}";
Iterable<DBObject> results = null;
try {
results = mapReduce(map.toString(), reduce, query);
} catch (MapReduceException ex) {
logger.error(ex.getMessage(), ex);
}
DBObject result = results.iterator().next();
DBObject dbo = (DBObject) result.get("value");
return Double.parseDouble(dbo.get("value").toString());
}
public double sum(String key) {
return sum(key, new BasicDBObject());
}
public double sum(String key, BuguQuery query) {
return sum(key, query.getCondition());
}
private double sum(String key, DBObject query) {
if (!this.exists(query)) {
return 0;
}
StringBuilder map = new StringBuilder("function(){emit('");
map.append(key);
map.append("', {'value':this.");
map.append(key);
map.append("});}");
String reduce = "function(key, values){var sum=0; for(var i=0;i<values.length; i++){sum+=values[i].value;} return {'value':sum}}";
Iterable<DBObject> results = null;
try {
results = mapReduce(map.toString(), reduce, query);
} catch (MapReduceException ex) {
logger.error(ex.getMessage(), ex);
}
DBObject result = results.iterator().next();
DBObject dbo = (DBObject) result.get("value");
return Double.parseDouble(dbo.get("value").toString());
}
public double average(String key) {
return average(key, new BasicDBObject());
}
public double average(String key, BuguQuery query) {
return average(key, query.getCondition());
}
private double average(String key, DBObject query) {
long count = this.count(query);
if (count == 0) {
return 0;
}
double sum = this.sum(key, query);
return sum / count;
}
public Iterable<DBObject> mapReduce(MapReduceCommand cmd) throws MapReduceException {
MapReduceOutput output = coll.mapReduce(cmd);
CommandResult cr = output.getCommandResult();
if (!cr.ok()) {
throw new MapReduceException(cr.getErrorMessage());
}
return output.results();
}
public Iterable<DBObject> mapReduce(String map, String reduce) throws MapReduceException {
MapReduceOutput output = coll.mapReduce(map, reduce, null, OutputType.INLINE, null);
CommandResult cr = output.getCommandResult();
if (!cr.ok()) {
throw new MapReduceException(cr.getErrorMessage());
}
return output.results();
}
public Iterable<DBObject> mapReduce(String map, String reduce, BuguQuery query) throws MapReduceException {
return mapReduce(map, reduce, query.getCondition());
}
private Iterable<DBObject> mapReduce(String map, String reduce, DBObject query) throws MapReduceException {
MapReduceOutput output = coll.mapReduce(map, reduce, null, OutputType.INLINE, query);
CommandResult cr = output.getCommandResult();
if (!cr.ok()) {
throw new MapReduceException(cr.getErrorMessage());
}
return output.results();
}
public Iterable<DBObject> mapReduce(String map, String reduce, String outputTarget, MapReduceCommand.OutputType outputType, String orderBy, BuguQuery query) throws MapReduceException {
return mapReduce(map, reduce, outputTarget, outputType, orderBy, query.getCondition());
}
private synchronized Iterable<DBObject> mapReduce(String map, String reduce, String outputTarget, MapReduceCommand.OutputType outputType, String orderBy, DBObject query) throws MapReduceException {
MapReduceOutput output = coll.mapReduce(map, reduce, outputTarget, outputType, query);
CommandResult cr = output.getCommandResult();
if (!cr.ok()) {
throw new MapReduceException(cr.getErrorMessage());
}
DBCollection c = output.getOutputCollection();
DBCursor cursor = null;
if (orderBy != null) {
cursor = c.find().sort(MapperUtil.getSort(orderBy));
} else {
cursor = c.find();
}
List<DBObject> list = new ArrayList<DBObject>();
for (Iterator<DBObject> it = cursor.iterator(); it.hasNext(); ) {
list.add(it.next());
}
return list;
}
public Iterable<DBObject> mapReduce(String map, String reduce, String outputTarget, MapReduceCommand.OutputType outputType, String orderBy, int pageNum, int pageSize, BuguQuery query) throws MapReduceException {
return mapReduce(map, reduce, outputTarget, outputType, orderBy, pageNum, pageSize, query.getCondition());
}
private synchronized Iterable<DBObject> mapReduce(String map, String reduce, String outputTarget, MapReduceCommand.OutputType outputType, String orderBy, int pageNum, int pageSize, DBObject query) throws MapReduceException {
MapReduceOutput output = coll.mapReduce(map, reduce, outputTarget, outputType, query);
CommandResult cr = output.getCommandResult();
if (!cr.ok()) {
throw new MapReduceException(cr.getErrorMessage());
}
DBCollection c = output.getOutputCollection();
DBCursor cursor = null;
if (orderBy != null) {
cursor = c.find().sort(MapperUtil.getSort(orderBy)).skip((pageNum - 1) * pageSize).limit(pageSize);
} else {
cursor = c.find().skip((pageNum - 1) * pageSize).limit(pageSize);
}
List<DBObject> list = new ArrayList<DBObject>();
for (Iterator<DBObject> it = cursor.iterator(); it.hasNext(); ) {
list.add(it.next());
}
return list;
}
/**
* Create an aggregation.
*
* @return a new BuguQuery object
*/
public BuguAggregation<T> aggregate() {
return new BuguAggregation<T>(coll);
}
/**
* Check if any entity match the condition
*
* @param query the condition
* @return
*/
private boolean exists(DBObject query) {
return coll.findOne(query) != null;
}
}