package org.yy.mongodb.client; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.bson.Document; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.mongodb.MongoDatabaseUtils; import org.springframework.data.mongodb.SessionSynchronization; import org.springframework.util.Assert; import org.yy.mongodb.client.event.ResultContext; import org.yy.mongodb.client.event.ResultHandler; import org.yy.mongodb.exception.MongoDaoException; import org.yy.mongodb.exception.MongoORMException; import org.yy.mongodb.orm.MqlMapConfiguration; import org.yy.mongodb.orm.engine.config.AggregateConfig; import org.yy.mongodb.orm.engine.config.CommandConfig; import org.yy.mongodb.orm.engine.config.DeleteConfig; import org.yy.mongodb.orm.engine.config.GroupConfig; import org.yy.mongodb.orm.engine.config.InsertConfig; import org.yy.mongodb.orm.engine.config.MapReduceConfig; import org.yy.mongodb.orm.engine.config.MappingConfig; import org.yy.mongodb.orm.engine.config.SelectConfig; import org.yy.mongodb.orm.engine.config.UpdateConfig; import org.yy.mongodb.orm.engine.entry.Entry; import org.yy.mongodb.orm.engine.entry.NodeEntry; import org.yy.mongodb.orm.engine.entry.Script; import org.yy.mongodb.orm.executor.parser.ResultExecutor; import org.yy.mongodb.util.BeanUtils; import org.yy.mongodb.util.NodeletUtils; import org.yy.mongodb.util.ScriptUtils; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBObject; import com.mongodb.ReadPreference; import com.mongodb.WriteConcern; import com.mongodb.client.AggregateIterable; import com.mongodb.client.DistinctIterable; import com.mongodb.client.FindIterable; import com.mongodb.client.MapReduceIterable; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.FindOneAndUpdateOptions; import com.mongodb.client.model.UpdateOptions; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.UpdateResult; /** * Templet for MongoDB. The primary Java interface implement for working with NoSql ORM. * * @author yy * @since 1.8 mongodb 3.4 */ @SuppressWarnings({"unchecked", "deprecation"}) public class MongoClientTemplet implements MongoTemplet, InitializingBean { private MongoFactoryBean factory; private MqlMapConfiguration configuration; private ResultHelper helper; /** * Mongo session synchronization. */ private SessionSynchronization sessionSynchronization = SessionSynchronization.ON_ACTUAL_TRANSACTION; @Override public void afterPropertiesSet() throws Exception { init(); } public void init() { Assert.notNull(factory, "Mongo orm factory not null."); configuration = factory.getConfiguration(); helper = new ResultHelper(); } @Override public <T> T findOne(String statement) { return findOne(statement, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> T findOne(String statement, Object parameter) { return findOne(statement, parameter, null, ReadPreference.secondaryPreferred()); } @Override public void findOne(String statement, ResultHandler handler) { findOne(statement, null, handler, ReadPreference.secondaryPreferred()); } @Override public void findOne(String statement, Object parameter, ResultHandler handler) { findOne(statement, parameter, handler, ReadPreference.secondaryPreferred()); } private <T> T findOne(String statement, Object parameter, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'findOne' mongodb command. Statement '" + statement + "'."); } SelectConfig config = (SelectConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Query statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); NodeEntry field = config.getField(); NodeEntry order = config.getOrder(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withReadPreference(readPreference); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> f = (Map<String, Object>) field.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> o = (Map<String, Object>) order.executorNode(config.getNamespace(), configuration, parameter); Document find = new Document(q); Document filter = (f == null) ? null : new Document(f); Document sort = (o == null) ? null : new Document(o); if (logger.isDebugEnabled()) { logger.debug("Execute 'findOne' mongodb command. Query '" + find + "'."); logger.debug("Execute 'findOne' mongodb command. Field '" + filter + "'."); logger.debug("Execute 'findOne' mongodb command. Order '" + sort + "'."); } Document doc = coll.find(find).filter(filter).sort(sort).first(); if (logger.isDebugEnabled()) { logger.debug("Execute 'findOne' mongodb command. Result is '" + doc + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return doc; } @Override public int getResultCount() { if (doc == null) { return 0; } return 1; } }); return null; } return (T) helper.toResult(config.getNamespace(), field, doc); } @Override public <T> List<T> find(String statement) { return find(statement, null, null, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> List<T> find(String statement, Object parameter) { return find(statement, parameter, null, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> List<T> find(String statement, Object parameter, Integer limit, Integer skip) { return find(statement, parameter, limit, skip, null, ReadPreference.secondaryPreferred()); } @Override public void find(String statement, ResultHandler handler) { find(statement, null, null, null, handler, ReadPreference.secondaryPreferred()); } @Override public void find(String statement, Object parameter, ResultHandler handler) { find(statement, parameter, null, null, handler, ReadPreference.secondaryPreferred()); } @Override public void find(String statement, Object parameter, Integer limit, Integer skip, ResultHandler handler) { find(statement, parameter, limit, skip, handler, ReadPreference.secondaryPreferred()); } private <T> List<T> find(String statement, Object parameter, Integer limit, Integer skip, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'find' mongodb command. Statement '" + statement + "'."); } SelectConfig config = (SelectConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Query statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); NodeEntry field = config.getField(); NodeEntry order = config.getOrder(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withReadPreference(readPreference); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> f = (Map<String, Object>) field.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> o = (Map<String, Object>) order.executorNode(config.getNamespace(), configuration, parameter); Document find = new Document(q); Document filter = (f == null) ? null : new Document(f); Document sort = (o == null) ? null : new Document(o); if (logger.isDebugEnabled()) { logger.debug("Execute 'find' mongodb command. Query '" + find + "'."); logger.debug("Execute 'find' mongodb command. Field '" + filter + "'."); logger.debug("Execute 'find' mongodb command. Order '" + sort + "'."); } FindIterable<Document> iterable = coll.find(find).filter(filter).sort(sort); if (skip != null) { iterable.skip(skip); } if (limit != null) { iterable.limit(limit); } List<Document> list = new ArrayList<Document>(); MongoCursor<Document> iterator = iterable.iterator(); while (iterator.hasNext()) { list.add(iterator.next()); } if (logger.isDebugEnabled()) { logger.debug("Execute 'find' mongodb command. Result set is '" + list + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return list; } @Override public int getResultCount() { return list.size(); } }); return null; } List<T> result = new ArrayList<T>(list.size()); list.forEach(item -> { result.add((T) helper.toResult(config.getNamespace(), field, item)); }); return result; } @Override public long count(String statement) { return count(statement, null); } @Override public long count(String statement, Object parameter) { if (logger.isDebugEnabled()) { logger.debug("Execute 'count' mongodb command. Statement '" + statement + "'."); } SelectConfig config = (SelectConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Count statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withReadPreference(ReadPreference.secondaryPreferred()); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Document count = new Document(q); if (logger.isDebugEnabled()) { logger.debug("Execute 'count' mongodb command. Query '" + count + "'."); } return coll.countDocuments(count); } @Override public <T> List<T> distinct(String statement, String key) { return distinct(statement, key, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> List<T> distinct(String statement, String key, Object parameter) { return distinct(statement, key, parameter, null, ReadPreference.secondaryPreferred()); } @Override public void distinct(String statement, String key, ResultHandler handler) { distinct(statement, key, null, handler, ReadPreference.secondaryPreferred()); } @Override public void distinct(String statement, String key, Object parameter, ResultHandler handler) { distinct(statement, key, parameter, handler, ReadPreference.secondaryPreferred()); } private <T> List<T> distinct(String statement, String key, Object parameter, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'distinct' mongodb command. Statement '" + statement + "'."); } SelectConfig config = (SelectConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Distinct statement id '" + statement + "' not found."); } if (StringUtils.isBlank(key)) { throw new MongoDaoException(statement, "Execute 'distinct' mongodb command. 'key' is blank."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); NodeEntry field = config.getField(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> f = (Map<String, Object>) field.executorNode(config.getNamespace(), configuration, parameter); Document distinct = new Document(q); Document filter = (f == null) ? null : new Document(f); if (logger.isDebugEnabled()) { logger.debug("Execute 'distinct' mongodb command. Query '" + distinct + "'."); logger.debug("Execute 'distinct' mongodb command. Field '" + filter + "'."); } DistinctIterable<Document> iterable = coll.distinct(key, distinct, Document.class); List<Document> list = new ArrayList<Document>(); MongoCursor<Document> iterator = iterable.iterator(); while (iterator.hasNext()) { list.add(iterator.next()); } if (logger.isDebugEnabled()) { logger.debug("Execute 'distinct' mongodb command. Result set '" + list + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return list; } @Override public int getResultCount() { return list.size(); } }); return null; } List<T> result = new ArrayList<T>(list.size()); list.forEach(item -> { result.add((T) helper.toResult(config.getNamespace(), field, item)); }); return result; } @Override public String insert(String statement) { return insert(statement, null); } @Override public String insert(String statement, Object parameter) { if (logger.isDebugEnabled()) { logger.debug("Execute 'insert' mongodb command. Statement '" + statement + "'."); } InsertConfig config = (InsertConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Insert statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry document = config.getDocument(); Entry selectKey = config.getSelectKey(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withWriteConcern(WriteConcern.ACKNOWLEDGED); Map<String, Object> doc = (Map<String, Object>) document.executorNode(config.getNamespace(), configuration, parameter); Document insert = new Document(doc); if (logger.isDebugEnabled()) { logger.debug("Execute 'insert' mongodb command. Doc '" + insert + "'."); } try { coll.insertOne(insert); } catch (Exception e) { throw new MongoDaoException(statement, "Execute 'insert' mongodb command has exception. The write was unacknowledged.", e); } String newId = insert.getObjectId("_id").toString(); if (logger.isDebugEnabled()) { logger.debug("Execute 'insert' mongodb command. ObjectId is '" + newId + "'."); } if (selectKey != null) { helper.setSelectKey(selectKey, newId, parameter); } return newId; } @Override public <T> List<String> insertBatch(String statement, List<T> list) { if (logger.isDebugEnabled()) { logger.debug("Execute 'insertBatch' mongodb command. Statement '" + statement + "'."); } InsertConfig config = (InsertConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Insert statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry document = config.getDocument(); Entry selectKey = config.getSelectKey(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withWriteConcern(WriteConcern.ACKNOWLEDGED); List<Document> documents = new ArrayList<Document>(list.size()); for (T parameter : list) { Map<String, Object> doc = (Map<String, Object>) document.executorNode(config.getNamespace(), configuration, parameter); Document d = new Document(doc); documents.add(d); if (logger.isDebugEnabled()) { logger.debug("Execute 'insert' mongodb command. Doc '" + d + "'."); } } try { coll.insertMany(documents); } catch (Exception e) { throw new MongoDaoException(statement, "Execute 'insert' mongodb command has exception. The write was unacknowledged.", e); } List<String> newIds = new ArrayList<String>(list.size()); for (Document doc : documents) { String newId = doc.getObjectId("_id").toString(); newIds.add(newId); if (logger.isDebugEnabled()) { logger.debug("Execute 'insert' mongodb command. ObjectId is '" + newId + "'."); } } if (selectKey != null) { for (int i = 0; i < list.size(); i++) { T parameter = list.get(i); helper.setSelectKey(selectKey, newIds.get(i), parameter); } } return newIds; } @Override public <T> T findAndModify(String statement) { return findAndModify(statement, null, null, false); } @Override public <T> T findAndModify(String statement, Object parameter) { return findAndModify(statement, parameter, null, false); } @Override public void findAndModify(String statement, ResultHandler handler) { findAndModify(statement, null, handler, false); } @Override public void findAndModify(String statement, Object parameter, ResultHandler handler) { findAndModify(statement, null, handler, false); } private <T> T findAndModify(String statement, Object parameter, ResultHandler handler, boolean upsert) { if (logger.isDebugEnabled()) { logger.debug("Execute 'findAndModify' mongodb command. Statement '" + statement + "'."); } UpdateConfig config = (UpdateConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "FindAndModify statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); NodeEntry action = config.getAction(); NodeEntry field = config.getField(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> a = (Map<String, Object>) action.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> f = (Map<String, Object>) field.executorNode(config.getNamespace(), configuration, parameter); Document filter = new Document(q); Document update = (a == null) ? null : new Document(a); Document fieldDbo = (f == null) ? null : new Document(f); if (logger.isDebugEnabled()) { logger.debug("Execute 'findAndModify' mongodb command. Query '" + filter + "'."); logger.debug("Execute 'findAndModify' mongodb command. Action '" + update + "'."); logger.debug("Execute 'findAndModify' mongodb command. Field '" + fieldDbo + "'."); } Document document = coll.findOneAndUpdate(filter, update, new FindOneAndUpdateOptions().upsert(upsert)); if (logger.isDebugEnabled()) { logger.debug("Execute 'findAndModify' mongodb command. Result is '" + document + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return document; } @Override public int getResultCount() { if (document == null) { return 0; } return 1; } }); return null; } return (T) helper.toResult(config.getNamespace(), field, document); } @Override public long update(String statement) { return update(statement, null); } @Override public long update(String statement, Object parameter) { if (logger.isDebugEnabled()) { logger.debug("Execute 'update' mongodb command. Statement '" + statement + "'."); } UpdateConfig config = (UpdateConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Update statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); NodeEntry action = config.getAction(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withWriteConcern(WriteConcern.ACKNOWLEDGED); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> a = (Map<String, Object>) action.executorNode(config.getNamespace(), configuration, parameter); Document filter = new Document(q); Document update = (a == null) ? null : new Document(a); if (logger.isDebugEnabled()) { logger.debug("Execute 'update' mongodb command. Query '" + filter + "'."); logger.debug("Execute 'update' mongodb command. Action '" + update + "'."); } UpdateResult result = coll.updateMany(filter, update, new UpdateOptions().upsert(false)); if (!result.wasAcknowledged()) { throw new MongoDaoException(statement, "Execute 'update' mongodb command has exception. The write was unacknowledged."); } return result.getModifiedCount(); } @Override public long delete(String statement) { return delete(statement, null); } @Override public long delete(String statement, Object parameter) { if (logger.isDebugEnabled()) { logger.debug("Execute 'delete' mongodb command. Statement '" + statement + "'."); } DeleteConfig config = (DeleteConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Delete statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry query = config.getQuery(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withWriteConcern(WriteConcern.ACKNOWLEDGED); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Document filter = new Document(q); if (logger.isDebugEnabled()) { logger.debug("Execute 'delete' mongodb command. Query '" + filter + "'."); } DeleteResult result = coll.deleteMany(filter); if (!result.wasAcknowledged()) { throw new MongoDaoException(statement, "Execute 'delete' mongodb command has exception. The write was unacknowledged."); } return result.getDeletedCount(); } @Override public <T> T command(String statement) { return command(statement, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> T command(String statement, Object parameter) { return command(statement, parameter, null, ReadPreference.secondaryPreferred()); } @Override public void command(String statement, ResultHandler handler) { command(statement, null, handler, ReadPreference.secondaryPreferred()); } @Override public void command(String statement, Object parameter, ResultHandler handler) { command(statement, parameter, handler, ReadPreference.secondaryPreferred()); } private <T> T command(String statement, Object parameter, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'command' mongodb command. Statement '" + statement + "'."); } CommandConfig config = (CommandConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Command statement id '" + statement + "' not found."); } NodeEntry query = config.getQuery(); NodeEntry field = config.getField(); MongoDatabase db = getDatabase(); Map<String, Object> q = (Map<String, Object>) query.executorNode(config.getNamespace(), configuration, parameter); Document command = new Document(q); if (logger.isDebugEnabled()) { logger.debug("Execute 'command' mongodb command. Query '" + command + "'."); } Document result = db.runCommand(command, readPreference); if (logger.isDebugEnabled()) { logger.debug("Execute 'command' mongodb command. Result set '" + result + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return result; } @Override public int getResultCount() { if (result == null) { return 0; } return 1; } }); return null; } return (T) helper.toResult(config.getNamespace(), field, result); } @Override public <T> T group(String statement) { return group(statement, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> T group(String statement, Object parameter) { return group(statement, parameter, null, ReadPreference.secondaryPreferred()); } @Override public void group(String statement, ResultHandler handler) { group(statement, null, handler, ReadPreference.secondaryPreferred()); } @Override public void group(String statement, Object parameter, ResultHandler handler) { group(statement, parameter, handler, ReadPreference.secondaryPreferred()); } private <T> T group(String statement, Object parameter, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'group' mongodb command. Statement '" + statement + "'."); } GroupConfig config = (GroupConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Group statement id '" + statement + "' not found."); } String collection = config.getCollection(); NodeEntry key = config.getKey(); Script keyf = config.getKeyf(); NodeEntry condition = config.getCondition(); NodeEntry initial = config.getInitial(); Script reduce = config.getReduce(); Script finalize = config.getFinalize(); NodeEntry field = config.getField(); Map<String, Object> k = (Map<String, Object>) key.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> c = (Map<String, Object>) condition.executorNode(config.getNamespace(), configuration, parameter); Map<String, Object> i = (Map<String, Object>) initial.executorNode(config.getNamespace(), configuration, parameter); String kf = ScriptUtils.fillScriptParams(keyf, parameter); String r = ScriptUtils.fillScriptParams(reduce, parameter); String f = ScriptUtils.fillScriptParams(finalize, parameter); DBObject keys = new BasicDBObject(k); DBObject condi = new BasicDBObject(c); DBObject initi = new BasicDBObject(i); if (logger.isDebugEnabled()) { logger.debug("Execute 'group' mongodb command. Key '" + keys + "'."); logger.debug("Execute 'group' mongodb command. Condition '" + condi + "'."); logger.debug("Execute 'group' mongodb command. Initial '" + initi + "'."); logger.debug("Execute 'group' mongodb command. Keyf '" + kf + "'."); logger.debug("Execute 'group' mongodb command. Reduce '" + r + "'."); logger.debug("Execute 'group' mongodb command. Finalize '" + f + "'."); } DB legacyDb = factory.getLegacyDb(); DBObject result = legacyDb.getCollection(collection).group(keys, condi, initi, r, f, readPreference); if (logger.isDebugEnabled()) { logger.debug("Execute 'group' mongodb command. Result set '" + result + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return result; } @Override public int getResultCount() { if (result == null) { return 0; } return 1; } }); return null; } return (T) helper.toResult(config.getNamespace(), field, result); } @Override public <T> List<T> aggregate(String statement) { return aggregate(statement, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> List<T> aggregate(String statement, Object parameter) { return aggregate(statement, parameter, null, ReadPreference.secondaryPreferred()); } @Override public void aggregate(String statement, ResultHandler handler) { aggregate(statement, null, handler, ReadPreference.secondaryPreferred()); } @Override public void aggregate(String statement, Object parameter, ResultHandler handler) { aggregate(statement, parameter, handler, ReadPreference.secondaryPreferred()); } private <T> List<T> aggregate(String statement, Object parameter, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'aggregate' mongodb command. Statement '" + statement + "'."); } AggregateConfig config = (AggregateConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "Aggregate statement id '" + statement + "' not found."); } String collection = config.getCollection(); Map<String, NodeEntry> function = config.getFunction(); NodeEntry field = config.getField(); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withReadPreference(readPreference); List<Document> operations = new ArrayList<Document>(function.size()); for (Map.Entry<String, NodeEntry> entry : function.entrySet()) { NodeEntry ne = entry.getValue(); Map<String, Object> op = (Map<String, Object>) ne.executorNode(config.getNamespace(), configuration, parameter); Document operation = new Document(op); operations.add(operation); if (logger.isDebugEnabled()) { logger.debug("Execute 'aggregate' mongodb command. Operation '" + operation + "'."); } } AggregateIterable<Document> iterable = coll.aggregate(operations); List<Document> list = new ArrayList<Document>(); MongoCursor<Document> iterator = iterable.iterator(); while (iterator.hasNext()) { list.add(iterator.next()); } if (logger.isDebugEnabled()) { logger.debug("Execute 'aggregate' mongodb command. Result set '" + list + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return list; } @Override public int getResultCount() { return list.size(); } }); return null; } List<T> result = new ArrayList<T>(list.size()); for (Document doc : list) { T t = (T) helper.toResult(config.getNamespace(), field, doc); result.add(t); } return result; } @Override public <T> List<T> mapReduce(String statement) { return mapReduce(statement, null, null, ReadPreference.secondaryPreferred()); } @Override public <T> List<T> mapReduce(String statement, Object parameter) { return mapReduce(statement, parameter, null, ReadPreference.secondaryPreferred()); } @Override public void mapReduce(String statement, ResultHandler handler) { mapReduce(statement, null, handler, ReadPreference.secondaryPreferred()); } @Override public void mapReduce(String statement, Object parameter, ResultHandler handler) { mapReduce(statement, parameter, handler, ReadPreference.secondaryPreferred()); } private <T> List<T> mapReduce(String statement, Object parameter, ResultHandler handler, ReadPreference readPreference) { if (logger.isDebugEnabled()) { logger.debug("Execute 'mapReduce' mongodb command. Statement '" + statement + "'."); } MapReduceConfig config = (MapReduceConfig) configuration.getStatement(statement); if (config == null) { throw new MongoDaoException(statement, "MapReduce statement id '" + statement + "' not found."); } String collection = config.getCollection(); Script map = config.getMap(); Script reduce = config.getReduce(); NodeEntry field = config.getField(); String m = ScriptUtils.fillScriptParams(map, parameter); String r = ScriptUtils.fillScriptParams(reduce, parameter); MongoDatabase db = getDatabase(); MongoCollection<Document> coll = db.getCollection(collection).withReadPreference(readPreference); MapReduceIterable<Document> iterable = coll.mapReduce(m, r); List<Document> list = new ArrayList<Document>(); MongoCursor<Document> iterator = iterable.iterator(); while (iterator.hasNext()) { list.add(iterator.next()); } if (logger.isDebugEnabled()) { logger.debug("Execute 'mapReduce' mongodb command. Result set '" + list + "'."); } if (handler != null) { handler.handleResult(new ResultContext() { @Override public Object getResultObject() { return list; } @Override public int getResultCount() { return list.size(); } }); return null; } List<T> result = new ArrayList<T>(list.size()); for (Document doc : list) { T t = (T) helper.toResult(config.getNamespace(), field, doc); result.add(t); } return result; } @Override public MongoDatabase getDatabase() { return MongoDatabaseUtils.getDatabase(factory, sessionSynchronization); } @Override public MongoDatabase getDatabase(String dbName) { if (StringUtils.isBlank(dbName)) { throw new MongoDaoException("getDatabase", "Execute get mongodb command. The db name is blank."); } return MongoDatabaseUtils.getDatabase(dbName, factory, sessionSynchronization); } @Override public <T> T parseObject(String mappingId, Document source) { MappingConfig mapping = (MappingConfig) configuration.getStatement(mappingId); NodeEntry nodeEntry = new NodeEntry(); nodeEntry.setClazz(mapping.getClazz()); nodeEntry.setNodeMappings(NodeletUtils.getMappingEntry(mapping, configuration)); return (T) helper.toResult(mapping.getNamespace(), nodeEntry, source); } /** * Helper for mongodb result. */ private class ResultHelper { private ResultExecutor resultExecutor; public ResultHelper() { resultExecutor = new ResultExecutor(); } public Object toResult(String namespace, NodeEntry entry, Object object) { return resultExecutor.parser(namespace, configuration, entry, object); } public void setSelectKey(Entry entry, String key, Object target) { if (target instanceof Map) { ((Map<Object, Object>) target).put(entry.getName(), key); } else { try { BeanUtils.setProperty(target, entry.getColumn(), key); } catch (Exception e) { throw new MongoORMException("No selectKey property '" + entry.getColumn() + "'found. Class '" + target.getClass() + "'.", e); } } } } public void setFactory(MongoFactoryBean factory) { this.factory = factory; } }