All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.MongoDBExecutor Maven / Gradle / Ivy

There is a newer version: 1.8.1
Show newest version
/*
 * Copyright (C) 2015 HaiYang Li
 *
 * 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 com.landawn.abacus.util;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import org.bson.BSONObject;
import org.bson.BasicBSONObject;
import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.Document;
import org.bson.codecs.BsonTypeClassMap;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.DocumentCodec;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

import com.landawn.abacus.DataSet;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.exception.AbacusException;
import com.landawn.abacus.parser.JSONParser;
import com.landawn.abacus.parser.ParserFactory;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.stream.Stream;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.bulk.BulkWriteResult;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import com.mongodb.client.model.BulkWriteOptions;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.InsertManyOptions;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.WriteModel;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;

/**
 * It's a simple wrapper of MongoDB Java client.
 * 
 * 
We recommend to define "id" property in java entity/bean as the object "_id" in MongoDB to keep things as simple as possible.
* * * @since 0.8 * * @author Haiyang Li * * @see com.mongodb.client.model.Filters * @see com.mongodb.client.model.Aggregates * @see com.mongodb.client.model.Accumulators * @see com.mongodb.client.model.Projections * @see com.mongodb.client.model.Sorts */ public final class MongoDBExecutor { /** * It's name of object id set in Map/Object array. */ public static final String _ID = "_id"; /** * Property name of id. */ public static final String ID = "id"; private static final JSONParser jsonParser = ParserFactory.createJSONParser(); // private static CodecRegistry codecRegistry = CodecRegistries.fromCodecs(new CalendarCodec(), new TimeCodec(), new TimestampCodec()); private static final CodecRegistry codecRegistry = CodecRegistries.fromRegistries(MongoClient.getDefaultCodecRegistry(), new GeneralCodecRegistry()); private static final Map, Method> classIdSetMethodPool = new ConcurrentHashMap<>(); private final Map collExecutorPool = new ConcurrentHashMap<>(); private final MongoDatabase mongoDB; private final AsyncExecutor asyncExecutor; private final AsyncMongoDBExecutor asyncDBExecutor; public MongoDBExecutor(final MongoDatabase mongoDB) { this(mongoDB, new AsyncExecutor(64, 300, TimeUnit.SECONDS)); } public MongoDBExecutor(final MongoDatabase mongoDB, final AsyncExecutor asyncExecutor) { this.mongoDB = mongoDB.withCodecRegistry(codecRegistry); this.asyncExecutor = asyncExecutor; this.asyncDBExecutor = new AsyncMongoDBExecutor(this, this.asyncExecutor); } public MongoDatabase mongoDB() { return mongoDB; } public AsyncMongoDBExecutor async() { return asyncDBExecutor; } public MongoCollectionExecutor collExecutor(final String collectionName) { MongoCollectionExecutor collExecutor = collExecutorPool.get(collectionName); if (collExecutor == null) { synchronized (collExecutorPool) { collExecutor = collExecutorPool.get(collectionName); if (collExecutor == null) { collExecutor = new MongoCollectionExecutor(this, mongoDB.getCollection(collectionName), asyncExecutor); collExecutorPool.put(collectionName, collExecutor); } } } return collExecutor; } public MongoCollection collection(final String collectionName) { return mongoDB.getCollection(collectionName); } public MongoCollection collection(final Class targetClass, final String collectionName) { return mongoDB.getCollection(collectionName, targetClass); } /** * The object id ("_id") property will be read from/write to the specified property * @param cls * @param idPropertyName */ public static void registerIdProeprty(final Class cls, final String idPropertyName) { if (ClassUtil.getPropGetMethod(cls, idPropertyName) == null || ClassUtil.getPropSetMethod(cls, idPropertyName) == null) { throw new IllegalArgumentException("The specified class: " + ClassUtil.getCanonicalClassName(cls) + " doesn't have getter or setter method for the specified id propery: " + idPropertyName); } final Method setMethod = ClassUtil.getPropSetMethod(cls, idPropertyName); final Class parameterType = setMethod.getParameterTypes()[0]; if (!(String.class.isAssignableFrom(parameterType) || ObjectId.class.isAssignableFrom(parameterType))) { throw new IllegalArgumentException( "The parameter type of the specified id setter method must be 'String' or 'ObjectId': " + setMethod.toGenericString()); } classIdSetMethodPool.put(cls, setMethod); } public static DataSet extractData(final MongoIterable findIterable) { return extractData(Map.class, findIterable); } /** * * @param targetClass an entity class with getter/setter method or Map.class/Document.class * @param findIterable * @return */ public static DataSet extractData(final Class targetClass, final MongoIterable findIterable) { return extractData(targetClass, null, findIterable); } /** * * @param targetClass an entity class with getter/setter method or Map.class/Document.class * @param selectPropNames * @param findIterable * @return */ static DataSet extractData(final Class targetClass, final Collection selectPropNames, final MongoIterable findIterable) { checkTargetClass(targetClass); final List rowList = findIterable.into(new ArrayList<>()); final Optional first = N.firstNonNull(rowList); if (first.isPresent()) { /* if (Map.class.isAssignableFrom(first.get().getClass())) { if (N.isNullOrEmpty(selectPropNames)) { final Set columnNames = new LinkedHashSet<>(); @SuppressWarnings("rawtypes") final List> tmp = (List) rowList; for (Map row : tmp) { columnNames.addAll(row.keySet()); } return N.newDataSet(columnNames, rowList); } else { return N.newDataSet(selectPropNames, rowList); } } else { return N.newDataSet(rowList); } */ if (Map.class.isAssignableFrom(targetClass) && Map.class.isAssignableFrom(first.get().getClass())) { if (N.isNullOrEmpty(selectPropNames)) { final Set columnNames = new LinkedHashSet<>(); @SuppressWarnings("rawtypes") final List> tmp = (List) rowList; for (Map row : tmp) { columnNames.addAll(row.keySet()); } return N.newDataSet(columnNames, rowList); } else { return N.newDataSet(selectPropNames, rowList); } } else if (Document.class.isAssignableFrom(first.get().getClass())) { final List newRowList = new ArrayList<>(rowList.size()); for (Object row : rowList) { newRowList.add(toEntity(targetClass, (Document) row)); } return N.newDataSet(selectPropNames, newRowList); } else { return N.newDataSet(selectPropNames, rowList); } } else { return N.newEmptyDataSet(); } } /** * * @param targetClass an entity class with getter/setter method, Map.class or basic single value type(Primitive/String/Date...) * @param findIterable * @return */ @SuppressWarnings("rawtypes") public static List toList(final Class targetClass, final MongoIterable findIterable) { final Type type = N.typeOf(targetClass); final List rowList = findIterable.into(new ArrayList<>()); final Optional first = N.firstNonNull(rowList); if (first.isPresent()) { if (targetClass.isAssignableFrom(first.getClass())) { return (List) rowList; } else { final List resultList = new ArrayList<>(rowList.size()); if (type.isEntity() || type.isMap()) { if (first.get() instanceof Document) { for (Object row : rowList) { resultList.add(toEntity(targetClass, (Document) row)); } } else if (type.isMap()) { for (Object row : rowList) { resultList.add(Maps.entity2Map((Map) N.newInstance(targetClass), row)); } } else { for (Object row : rowList) { resultList.add(N.copy(targetClass, row)); } } } else if (first.get() instanceof Map && ((Map) first.get()).size() == 1) { final Map m = (Map) first.get(); final String propName = m.keySet().iterator().next(); if (m.get(propName) != null && targetClass.isAssignableFrom(m.get(propName).getClass())) { for (Object row : rowList) { resultList.add(((Map) row).get(propName)); } } else { for (Object row : rowList) { resultList.add(N.as(targetClass, ((Map) row).get(propName))); } } } else { throw new IllegalArgumentException( "Can't covert document: " + first.toString() + " to class: " + ClassUtil.getCanonicalClassName(targetClass)); } return (List) resultList; } } else { return new ArrayList<>(); } } /** * The id in the specified doc will be set to the returned object if and only if the id is not null or empty and it's acceptable to the targetClass. * * @param targetClass an entity class with getter/setter method, Map.class or basic single value type(Primitive/String/Date...) * @param doc * @return */ @SuppressWarnings("deprecation") public static T toEntity(final Class targetClass, final Document doc) { checkTargetClass(targetClass); if (Map.class.isAssignableFrom(targetClass)) { // return (T) new LinkedHashMap<>(doc); if (targetClass.isAssignableFrom(doc.getClass())) { return (T) doc; } else { final Map map = (Map) N.newInstance(targetClass); map.putAll(doc); return (T) map; } } final Method idSetMethod = getObjectIdSetMethod(targetClass); final Class parameterType = idSetMethod == null ? null : idSetMethod.getParameterTypes()[0]; final Object objectId = doc.getObjectId(_ID); T entity = null; doc.remove(_ID); try { entity = Maps.map2Entity(targetClass, doc); if (objectId != null && parameterType != null) { if (parameterType.isAssignableFrom(objectId.getClass())) { ClassUtil.setPropValue(entity, idSetMethod, objectId); } else if (parameterType.isAssignableFrom(String.class)) { ClassUtil.setPropValue(entity, idSetMethod, objectId.toString()); } else { ClassUtil.setPropValue(entity, idSetMethod, objectId); } } } finally { doc.put(_ID, objectId); } if (N.isDirtyMarker(entity.getClass())) { ((DirtyMarker) entity).markDirty(false); } return entity; } private static Method getObjectIdSetMethod(final Class targetClass) { Method idSetMethod = classIdSetMethodPool.get(targetClass); if (idSetMethod == null) { Method idPropSetMethod = ClassUtil.getPropSetMethod(targetClass, ID); Class parameterType = idPropSetMethod == null ? null : idPropSetMethod.getParameterTypes()[0]; // if (parameterType != null && (ObjectId.class.isAssignableFrom(parameterType) || String.class.isAssignableFrom(parameterType))) { // idSetMethod = idPropSetMethod; // } if (parameterType != null && ObjectId.class.isAssignableFrom(parameterType)) { idSetMethod = idPropSetMethod; } if (idSetMethod == null) { idSetMethod = ClassUtil.METHOD_MASK; } classIdSetMethodPool.put(targetClass, idSetMethod); } return idSetMethod == ClassUtil.METHOD_MASK ? null : idSetMethod; } public static String toJSON(final Bson bson) { return bson instanceof Map ? N.toJSON(bson) : N.toJSON(bson.toBsonDocument(Document.class, codecRegistry)); } public static String toJSON(final BSONObject bsonObject) { return bsonObject instanceof Map ? N.toJSON(bsonObject) : N.toJSON(bsonObject.toMap()); } public static String toJSON(final BasicDBObject bsonObject) { return bsonObject instanceof Map ? N.toJSON(bsonObject) : N.toJSON(bsonObject.toMap()); } /** * Returns an instance of the specified target class with the property values from the specified JSON String. * * @param targetClass Bson.class, Document.class, BasicBSONObject.class, BasicDBObject.class * @param json * @return */ public static T fromJSON(final Class targetClass, final String json) { if (targetClass.equals(Bson.class) || targetClass.equals(Document.class)) { final Document doc = new Document(); jsonParser.readString(doc, json); return (T) doc; } else if (targetClass.equals(BasicBSONObject.class)) { final BasicBSONObject result = new BasicBSONObject(); jsonParser.readString(result, json); return (T) result; } else if (targetClass.equals(BasicDBObject.class)) { final BasicDBObject result = new BasicDBObject(); jsonParser.readString(result, json); return (T) result; } else { throw new IllegalArgumentException("Unsupported type: " + ClassUtil.getCanonicalClassName(targetClass)); } } /** * * @param obj an array of pairs of property name and value/Map or an entity with getter/setter methods. * @return */ public static Bson toBson(final Object obj) { return toDocument(obj); } /** * Create a new document with specified parameter(s). It could an array of property name and value, or a map, or an entity. * * @param a * @return */ @SafeVarargs public static Bson toBson(final Object... a) { return toDocument(a); } /** * * @param obj an array of pairs of property name and value/Map or an entity with getter/setter methods. * @return */ public static Document toDocument(final Object obj) { return toDocument(obj, false); } /** * Create a new document with specified parameter(s). It could an array of property name and value, or a map, or an entity. * * @param a * @return */ @SafeVarargs public static Document toDocument(final Object... a) { if (N.isNullOrEmpty(a)) { return new Document(); } return a.length == 1 ? toDocument(a[0]) : toDocument((Object) a); } @SuppressWarnings("deprecation") static Document toDocument(final Object obj, final boolean isForUpdate) { final Document result = new Document(); if (obj instanceof Map) { result.putAll((Map) obj); } else if (N.isEntity(obj.getClass())) { if (obj instanceof DirtyMarker) { final Class srCls = obj.getClass(); final Set updatePropNames = isForUpdate ? ((DirtyMarker) obj).dirtyPropNames() : ((DirtyMarker) obj).signedPropNames(); if (updatePropNames.size() == 0) { // logger.warn("No property is signed/updated in the specified source entity: " + N.toString(obj)); } else { Method propGetMethod = null; Object propValue = null; for (String propName : updatePropNames) { propGetMethod = ClassUtil.getPropGetMethod(srCls, propName); propName = ClassUtil.getPropNameByMethod(propGetMethod); propValue = ClassUtil.getPropValue(obj, propGetMethod); result.put(propName, propValue); } } } else { final Map getterMethodList = ClassUtil.getPropGetMethodList(obj.getClass()); if (getterMethodList.size() == 0) { throw new IllegalArgumentException("No property getter/setter method found in the specified entity: " + obj.getClass().getCanonicalName()); } String propName = null; Object propValue = null; for (Map.Entry entry : getterMethodList.entrySet()) { propName = entry.getKey(); propValue = ClassUtil.getPropValue(obj, entry.getValue()); if (propValue == null) { continue; } result.put(propName, propValue); } } } else if (obj instanceof Object[]) { final Object[] a = (Object[]) obj; if (0 != (a.length % 2)) { throw new IllegalArgumentException( "The parameters must be the pairs of property name and value, or Map, or an entity class with getter/setter methods."); } for (int i = 0; i < a.length; i++) { result.put((String) a[i], a[++i]); } } else { throw new IllegalArgumentException("The parameters must be a Map, or an entity class with getter/setter methods"); } resetObjectId(obj, result); return result; } /** * * @param obj an array of pairs of property name and value/Map or an entity with getter/setter methods. * @return */ public static BasicBSONObject toBSONObject(final Object obj) { final BasicBSONObject result = new BasicBSONObject(); if (obj instanceof Map) { result.putAll((Map) obj); } else if (N.isEntity(obj.getClass())) { Maps.deepEntity2Map(result, obj); } else if (obj instanceof Object[]) { final Object[] a = (Object[]) obj; if (0 != (a.length % 2)) { throw new IllegalArgumentException( "The parameters must be the pairs of property name and value, or Map, or an entity class with getter/setter methods."); } for (int i = 0; i < a.length; i++) { result.put((String) a[i], a[++i]); } } else { throw new IllegalArgumentException("The parameters must be a Map, or an entity class with getter/setter methods"); } resetObjectId(obj, result); return result; } @SafeVarargs public static BasicBSONObject toBSONObject(final Object... a) { if (N.isNullOrEmpty(a)) { return new BasicBSONObject(); } return a.length == 1 ? toBSONObject(a[0]) : toBSONObject((Object) a); } /** * * @param obj an array of pairs of property name and value/Map or an entity with getter/setter methods. * @return */ public static BasicDBObject toDBObject(final Object obj) { final BasicDBObject result = new BasicDBObject(); if (obj instanceof Map) { result.putAll((Map) obj); } else if (N.isEntity(obj.getClass())) { Maps.deepEntity2Map(result, obj); } else if (obj instanceof Object[]) { final Object[] a = (Object[]) obj; if (0 != (a.length % 2)) { throw new IllegalArgumentException( "The parameters must be the pairs of property name and value, or Map, or an entity class with getter/setter methods."); } for (int i = 0; i < a.length; i++) { result.put((String) a[i], a[++i]); } } else { throw new IllegalArgumentException("The parameters must be a Map, or an entity class with getter/setter methods"); } resetObjectId(obj, result); return result; } @SafeVarargs public static BasicDBObject toDBObject(final Object... a) { if (N.isNullOrEmpty(a)) { return new BasicDBObject(); } return a.length == 1 ? toDBObject(a[0]) : toDBObject((Object) a); } private static void resetObjectId(final Object obj, final Map doc) { final Class cls = obj.getClass(); final Method idSetMethod = getObjectIdSetMethod(obj.getClass()); final String idPropertyName = N.isEntity(cls) ? (idSetMethod == null ? null : ClassUtil.getPropNameByMethod(idSetMethod)) : _ID; if (idPropertyName != null && doc.containsKey(idPropertyName)) { Object id = doc.remove(idPropertyName); try { if (id instanceof String) { id = new ObjectId((String) id); } else if (id instanceof Date) { id = new ObjectId((Date) id); } else if (id instanceof byte[]) { id = new ObjectId((byte[]) id); } } finally { doc.put(_ID, id); } } } public boolean exists(final String collectionName, final String objectId) { return collExecutor(collectionName).exists(objectId); } public boolean exists(final String collectionName, final ObjectId objectId) { return collExecutor(collectionName).exists(objectId); } public boolean exists(final String collectionName, final Bson filter) { return collExecutor(collectionName).exists(filter); } public long count(final String collectionName) { return collExecutor(collectionName).count(); } public long count(final String collectionName, final Bson filter) { return collExecutor(collectionName).count(filter); } public long count(final String collectionName, final Bson filter, final CountOptions options) { return collExecutor(collectionName).count(filter, options); } public Document get(final String collectionName, final String objectId) { return collExecutor(collectionName).get(objectId); } public Document get(final String collectionName, final ObjectId objectId) { return collExecutor(collectionName).get(objectId); } public T get(final Class targetClass, final String collectionName, final String objectId) { return collExecutor(collectionName).get(targetClass, objectId); } public T get(final Class targetClass, final String collectionName, final ObjectId objectId) { return collExecutor(collectionName).get(targetClass, objectId); } public T get(final Class targetClass, final String collectionName, final String objectId, final Collection selectPropNames) { return collExecutor(collectionName).get(targetClass, objectId, selectPropNames); } public T get(final Class targetClass, final String collectionName, final ObjectId objectId, final Collection selectPropNames) { return collExecutor(collectionName).get(targetClass, objectId, selectPropNames); } public Optional gett(final String collectionName, final String objectId) { return collExecutor(collectionName).gett(objectId); } public Optional gett(final String collectionName, final ObjectId objectId) { return collExecutor(collectionName).gett(objectId); } public Optional gett(final Class targetClass, final String collectionName, final String objectId) { return collExecutor(collectionName).gett(targetClass, objectId); } public Optional gett(final Class targetClass, final String collectionName, final ObjectId objectId) { return collExecutor(collectionName).gett(targetClass, objectId); } public Optional gett(final Class targetClass, final String collectionName, final String objectId, final Collection selectPropNames) { return collExecutor(collectionName).gett(targetClass, objectId, selectPropNames); } public Optional gett(final Class targetClass, final String collectionName, final ObjectId objectId, final Collection selectPropNames) { return collExecutor(collectionName).gett(targetClass, objectId, selectPropNames); } @Beta public OptionalBoolean queryForBoolean(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForBoolean(propName, filter); } @Beta public OptionalChar queryForChar(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForChar(propName, filter); } @Beta public OptionalByte queryForByte(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForByte(propName, filter); } @Beta public OptionalShort queryForShort(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForShort(propName, filter); } @Beta public OptionalInt queryForInt(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForInt(propName, filter); } @Beta public OptionalLong queryForLong(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForLong(propName, filter); } @Beta public OptionalFloat queryForFloat(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForFloat(propName, filter); } @Beta public OptionalDouble queryForDouble(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForDouble(propName, filter); } public Nullable queryForString(final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForString(propName, filter); } public Nullable queryForSingleResult(final Class targetClass, final String collectionName, final String propName, final Bson filter) { return collExecutor(collectionName).queryForSingleResult(targetClass, propName, filter); } public Optional queryForEntity(final String collectionName, final Bson filter) { return collExecutor(collectionName).queryForEntity(filter); } public Optional queryForEntity(final Class targetClass, final String collectionName, final Bson filter) { return collExecutor(collectionName).queryForEntity(targetClass, filter); } public Optional queryForEntity(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter) { return collExecutor(collectionName).queryForEntity(targetClass, selectPropNames, filter); } public Optional queryForEntity(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort) { return collExecutor(collectionName).queryForEntity(targetClass, selectPropNames, filter, sort); } public Optional queryForEntity(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection) { return collExecutor(collectionName).queryForEntity(targetClass, filter, sort, projection); } public List find(final String collectionName, final Bson filter) { return collExecutor(collectionName).find(filter); } public List find(final Class targetClass, final String collectionName, final Bson filter) { return collExecutor(collectionName).find(targetClass, filter); } public List find(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter) { return collExecutor(collectionName).find(targetClass, selectPropNames, filter); } public List find(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final int offset, final int count) { return collExecutor(collectionName).find(targetClass, selectPropNames, filter, offset, count); } public List find(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort) { return collExecutor(collectionName).find(targetClass, selectPropNames, filter, sort); } /** * * @param targetClass an entity class with getter/setter method, Map.class or basic single value type(Primitive/String/Date...) * @param collectionName * @param selectPropNames * @param filter * @param sort * @param offset * @param count * @return */ public List find(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort, final int offset, final int count) { return collExecutor(collectionName).find(targetClass, selectPropNames, filter, sort, offset, count); } public List find(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection) { return collExecutor(collectionName).find(targetClass, filter, sort, projection); } /** * * @param targetClass an entity class with getter/setter method, Map.class or basic single value type(Primitive/String/Date...) * @param collectionName * @param filter * @param sort * @param projection * @param offset * @param count * @return */ public List find(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection, final int offset, final int count) { return collExecutor(collectionName).find(targetClass, filter, sort, projection, offset, count); } public DataSet query(final String collectionName, final Bson filter) { return collExecutor(collectionName).query(filter); } public DataSet query(final Class targetClass, final String collectionName, final Bson filter) { return collExecutor(collectionName).query(targetClass, filter); } public DataSet query(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter) { return collExecutor(collectionName).query(targetClass, selectPropNames, filter); } public DataSet query(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final int offset, final int count) { return collExecutor(collectionName).query(targetClass, selectPropNames, filter, offset, count); } public DataSet query(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort) { return collExecutor(collectionName).query(targetClass, selectPropNames, filter, sort); } public DataSet query(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort, final int offset, final int count) { return collExecutor(collectionName).query(targetClass, selectPropNames, filter, sort, offset, count); } public DataSet query(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection) { return collExecutor(collectionName).query(targetClass, filter, sort, projection); } public DataSet query(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection, final int offset, final int count) { return collExecutor(collectionName).query(targetClass, filter, sort, projection, offset, count); } public Stream stream(final String collectionName, final Bson filter) { return collExecutor(collectionName).stream(filter); } public Stream stream(final Class targetClass, final String collectionName, final Bson filter) { return collExecutor(collectionName).stream(targetClass, filter); } public Stream stream(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter) { return collExecutor(collectionName).stream(targetClass, selectPropNames, filter); } public Stream stream(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final int offset, final int count) { return collExecutor(collectionName).stream(targetClass, selectPropNames, filter, offset, count); } public Stream stream(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort) { return collExecutor(collectionName).stream(targetClass, selectPropNames, filter, sort); } public Stream stream(final Class targetClass, final String collectionName, final Collection selectPropNames, final Bson filter, final Bson sort, final int offset, final int count) { return collExecutor(collectionName).stream(targetClass, selectPropNames, filter, sort, offset, count); } public Stream stream(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection) { return collExecutor(collectionName).stream(targetClass, filter, sort, projection); } public Stream stream(final Class targetClass, final String collectionName, final Bson filter, final Bson sort, final Bson projection, final int offset, final int count) { return collExecutor(collectionName).stream(targetClass, filter, sort, projection, offset, count); } /** * * @param collectionName * @param obj can be Document/Map/entity class with getter/setter method. */ public void insert(final String collectionName, final Object obj) { collExecutor(collectionName).insert(obj); } /** * * @param collectionName * @param objList list of Document/Map/entity class with getter/setter method. * @deprecated replaced with {@code insertAll}. */ @Deprecated public void insert(final String collectionName, final Collection objList) { collExecutor(collectionName).insert(objList); } /** * * @param collectionName * @param objList list of Document/Map/entity class with getter/setter method. * @param options * @deprecated replaced with {@code insertAll}. */ @Deprecated public void insert(final String collectionName, final Collection objList, final InsertManyOptions options) { collExecutor(collectionName).insert(objList, options); } /** * * @param collectionName * @param objList list of Document/Map/entity class with getter/setter method. */ public void insertAll(final String collectionName, final Collection objList) { collExecutor(collectionName).insertAll(objList); } /** * * @param collectionName * @param objList list of Document/Map/entity class with getter/setter method. * @param options */ public void insertAll(final String collectionName, final Collection objList, final InsertManyOptions options) { collExecutor(collectionName).insertAll(objList, options); } /** * Update the record in data store with the properties which have been updated/set in the specified update by the specified objectId. * if the update implements DirtyMarker interface, just update the dirty properties. * * @param collectionName * @param objectId * @param update can be Bson/Document/Map/entity class with getter/setter method. * @return */ public UpdateResult update(final String collectionName, final String objectId, final Object update) { return collExecutor(collectionName).update(objectId, update); } /** * Update the record in data store with the properties which have been updated/set in the specified update by the specified objectId. * if the update implements DirtyMarker interface, just update the dirty properties. * * @param collectionName * @param objectId * @param update can be Bson/Document/Map/entity class with getter/setter method. * @return */ public UpdateResult update(final String collectionName, final ObjectId objectId, final Object update) { return collExecutor(collectionName).update(objectId, update); } /** * Just update one record in data store with the properties which have been updated/set in the specified update by the specified filter. * if the update implements DirtyMarker interface, just update the dirty properties. * * @param collectionName * @param filter * @param update can be Bson/Document/Map/entity class with getter/setter method. * @return */ public UpdateResult updateOne(final String collectionName, final Bson filter, final Object update) { return collExecutor(collectionName).updateOne(filter, update); } /** * Just update one record in data store with the properties which have been updated/set in the specified update by the specified filter. * if the update implements DirtyMarker interface, just update the dirty properties. * * @param collectionName * @param filter * @param update can be Bson/Document/Map/entity class with getter/setter method. * @param options * @return */ public UpdateResult updateOne(final String collectionName, final Bson filter, final Object update, final UpdateOptions options) { return collExecutor(collectionName).updateOne(filter, update, options); } /** * Update the records in data store with the properties which have been updated/set in the specified update by the specified filter. * if the update implements DirtyMarker interface, just update the dirty properties. * * @param collectionName * @param filter * @param update can be Bson/Document/Map/entity class with getter/setter method. * @return */ public UpdateResult updateAll(final String collectionName, final Bson filter, final Object update) { return collExecutor(collectionName).updateAll(filter, update); } /** * Update the records in data store with the properties which have been updated/set in the specified update by the specified filter. * if the update implements DirtyMarker interface, just update the dirty properties. * * @param collectionName * @param filter * @param update can be Bson/Document/Map/entity class with getter/setter method. * @param options * @return */ public UpdateResult updateAll(final String collectionName, final Bson filter, final Object update, final UpdateOptions options) { return collExecutor(collectionName).updateAll(filter, update, options); } /** * * @param collectionName * @param objectId * @param replacement can be Document/Map/entity class with getter/setter method. * @return */ public UpdateResult replace(final String collectionName, final String objectId, final Object replacement) { return collExecutor(collectionName).replace(objectId, replacement); } /** * * @param collectionName * @param objectId * @param replacement can be Document/Map/entity class with getter/setter method. * @return */ public UpdateResult replace(final String collectionName, final ObjectId objectId, final Object replacement) { return collExecutor(collectionName).replace(objectId, replacement); } /** * * @param collectionName * @param filter * @param replacement can be Document/Map/entity class with getter/setter method. * @return */ public UpdateResult replaceOne(final String collectionName, final Bson filter, final Object replacement) { return collExecutor(collectionName).replaceOne(filter, replacement); } /** * * @param collectionName * @param filter * @param replacement can be Document/Map/entity class with getter/setter method. * @param options * @return */ public UpdateResult replaceOne(final String collectionName, final Bson filter, final Object replacement, final UpdateOptions options) { return collExecutor(collectionName).replaceOne(filter, replacement, options); } public DeleteResult delete(final String collectionName, final String objectId) { return collExecutor(collectionName).delete(objectId); } public DeleteResult delete(final String collectionName, final ObjectId objectId) { return collExecutor(collectionName).delete(objectId); } public DeleteResult deleteOne(final String collectionName, final Bson filter) { return collExecutor(collectionName).deleteOne(filter); } public DeleteResult deleteAll(final String collectionName, final Bson filter) { return collExecutor(collectionName).deleteAll(filter); } public int bulkInsert(final String collectionName, final Collection entities) { return collExecutor(collectionName).bulkInsert(entities); } public int bulkInsert(final String collectionName, final Collection entities, final BulkWriteOptions options) { return collExecutor(collectionName).bulkInsert(entities, options); } public BulkWriteResult bulkWrite(final String collectionName, final List> requests) { return collExecutor(collectionName).bulkWrite(requests); } public BulkWriteResult bulkWrite(final String collectionName, final List> requests, final BulkWriteOptions options) { return collExecutor(collectionName).bulkWrite(requests, options); } public Stream distinct(final Class targetClass, final String collectionName, final String fieldName) { return collExecutor(collectionName).distinct(targetClass, fieldName); } public Stream distinct(final Class targetClass, final String collectionName, final String fieldName, final Bson filter) { return collExecutor(collectionName).distinct(targetClass, fieldName, filter); } public Stream aggregate(final String collectionName, final List pipeline) { return collExecutor(collectionName).aggregate(pipeline); } public Stream aggregate(final Class targetClass, final String collectionName, final List pipeline) { return collExecutor(collectionName).aggregate(targetClass, pipeline); } public Stream mapReduce(final String collectionName, final String mapFunction, final String reduceFunction) { return collExecutor(collectionName).mapReduce(mapFunction, reduceFunction); } public Stream mapReduce(final Class targetClass, final String collectionName, final String mapFunction, final String reduceFunction) { return collExecutor(collectionName).mapReduce(targetClass, mapFunction, reduceFunction); } @Beta public Stream groupBy(final String collectionName, final String fieldName) { return collExecutor(collectionName).groupBy(fieldName); } @Beta public Stream groupBy(final String collectionName, final Collection fieldNames) { return collExecutor(collectionName).groupBy(fieldNames); } @Beta public Stream groupByAndCount(final String collectionName, final String fieldName) { return collExecutor(collectionName).groupByAndCount(fieldName); } @Beta public Stream groupByAndCount(final String collectionName, final Collection fieldNames) { return collExecutor(collectionName).groupByAndCount(fieldNames); } private static void checkTargetClass(final Class targetClass) { if (!(N.isEntity(targetClass) || Map.class.isAssignableFrom(targetClass))) { throw new AbacusException("The target class must be an entity class with getter/setter methods or Map.class/Document.class. But it is: " + ClassUtil.getCanonicalClassName(targetClass)); } } private static class GeneralCodecRegistry implements CodecRegistry { private static final Map, Codec> pool = new ObjectPool, Codec>(128); @Override public Codec get(final Class clazz) { Codec codec = pool.get(clazz); if (codec == null) { codec = new GeneralCodec(clazz); pool.put(clazz, codec); } return (Codec) codec; } } private static class GeneralCodec implements Codec { private static final DocumentCodec documentCodec = new DocumentCodec(codecRegistry, new BsonTypeClassMap()); private final Class cls; private final boolean isEntityClass; public GeneralCodec(final Class cls) { this.cls = cls; isEntityClass = N.isEntity(cls); } @Override public void encode(final BsonWriter writer, final T value, final EncoderContext encoderContext) { if (isEntityClass) { documentCodec.encode(writer, toDocument(value), encoderContext); } else { writer.writeString(N.stringOf(value)); } } @Override public T decode(final BsonReader reader, final DecoderContext decoderContext) { if (isEntityClass) { return toEntity(cls, documentCodec.decode(reader, decoderContext)); } else { return N.valueOf(cls, reader.readString()); } } @Override public Class getEncoderClass() { return cls; } } }