com.mongodb.DB Maven / Gradle / Ivy
/*
* Copyright 2008-present MongoDB, Inc.
*
* 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.mongodb;
import com.mongodb.annotations.ThreadSafe;
import com.mongodb.client.internal.MongoIterableImpl;
import com.mongodb.client.internal.OperationExecutor;
import com.mongodb.client.model.Collation;
import com.mongodb.client.model.DBCreateViewOptions;
import com.mongodb.client.model.ValidationAction;
import com.mongodb.client.model.ValidationLevel;
import com.mongodb.internal.operation.BatchCursor;
import com.mongodb.internal.operation.CommandReadOperation;
import com.mongodb.internal.operation.CreateCollectionOperation;
import com.mongodb.internal.operation.CreateViewOperation;
import com.mongodb.internal.operation.DropDatabaseOperation;
import com.mongodb.internal.operation.ListCollectionsOperation;
import com.mongodb.internal.operation.ReadOperation;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;
import org.bson.BsonDocumentWrapper;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.Codec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static com.mongodb.DBCollection.createWriteConcernException;
import static com.mongodb.MongoNamespace.checkDatabaseNameValidity;
import static com.mongodb.ReadPreference.primary;
import static com.mongodb.assertions.Assertions.notNull;
/**
* A thread-safe client view of a logical database in a MongoDB cluster. A DB instance can be achieved from a {@link MongoClient} instance
* using code like:
*
* {@code
* MongoClient mongoClient = new MongoClient();
* DB db = mongoClient.getDB("");
* }
*
*
* See {@link MongoClient#getDB(String)} for further information about the effective deprecation of this class.
*
* @mongodb.driver.manual reference/glossary/#term-database Database
* @see MongoClient
*/
@ThreadSafe
@SuppressWarnings("deprecation")
public class DB {
private final MongoClient mongo;
private final String name;
private final OperationExecutor executor;
private final ConcurrentHashMap collectionCache;
private final Codec commandCodec;
private volatile ReadPreference readPreference;
private volatile WriteConcern writeConcern;
private volatile ReadConcern readConcern;
DB(final MongoClient mongo, final String name, final OperationExecutor executor) {
checkDatabaseNameValidity(name);
this.mongo = mongo;
this.name = name;
this.executor = executor;
this.collectionCache = new ConcurrentHashMap<>();
this.commandCodec = new DBObjectCodec(mongo.getCodecRegistry());
}
/**
* Gets the MongoClient instance
*
* @return the MongoClient instance that this database was constructed from
* @throws IllegalStateException if this DB was not created from a MongoClient instance
* @since 3.9
*/
public MongoClient getMongoClient() {
return mongo;
}
/**
* Sets the read preference for this database. Will be used as default for read operations from any collection in this database. See the
* documentation for {@link ReadPreference} for more information.
*
* @param readPreference {@code ReadPreference} to use
* @mongodb.driver.manual core/read-preference/ Read Preference
*/
public void setReadPreference(final ReadPreference readPreference) {
this.readPreference = readPreference;
}
/**
* Sets the write concern for this database. It will be used for write operations to any collection in this database. See the
* documentation for {@link WriteConcern} for more information.
*
* @param writeConcern {@code WriteConcern} to use
* @mongodb.driver.manual core/write-concern/ Write Concern
*/
public void setWriteConcern(final WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}
/**
* Gets the read preference for this database.
*
* @return {@code ReadPreference} to be used for read operations, if not specified explicitly
* @mongodb.driver.manual core/read-preference/ Read Preference
*/
public ReadPreference getReadPreference() {
return readPreference != null ? readPreference : mongo.getReadPreference();
}
/**
* Gets the write concern for this database.
*
* @return {@code WriteConcern} to be used for write operations, if not specified explicitly
* @mongodb.driver.manual core/write-concern/ Write Concern
*/
public WriteConcern getWriteConcern() {
return writeConcern != null ? writeConcern : mongo.getWriteConcern();
}
/**
* Sets the read concern for this database.
*
* @param readConcern the read concern to use for this collection
* @since 3.3
* @mongodb.server.release 3.2
* @mongodb.driver.manual reference/readConcern/ Read Concern
*/
public void setReadConcern(final ReadConcern readConcern) {
this.readConcern = readConcern;
}
/**
* Get the read concern for this database.
*
* @return the {@link com.mongodb.ReadConcern}
* @since 3.3
* @mongodb.server.release 3.2
* @mongodb.driver.manual reference/readConcern/ Read Concern
*/
public ReadConcern getReadConcern() {
return readConcern != null ? readConcern : mongo.getReadConcern();
}
/**
* Gets a collection with a given name.
*
* @param name the name of the collection to return
* @return the collection
* @throws IllegalArgumentException if the name is invalid
* @see MongoNamespace#checkCollectionNameValidity(String)
*/
public DBCollection getCollection(final String name) {
DBCollection collection = collectionCache.get(name);
if (collection != null) {
return collection;
}
collection = new DBCollection(name, this, executor);
if (mongo.getMongoClientOptions().getDbDecoderFactory() != DefaultDBDecoder.FACTORY) {
collection.setDBDecoderFactory(mongo.getMongoClientOptions().getDbDecoderFactory());
}
if (mongo.getMongoClientOptions().getDbEncoderFactory() != DefaultDBEncoder.FACTORY) {
collection.setDBEncoderFactory(mongo.getMongoClientOptions().getDbEncoderFactory());
}
DBCollection old = collectionCache.putIfAbsent(name, collection);
return old != null ? old : collection;
}
/**
* Drops this database. Removes all data on disk. Use with caution.
*
* @throws MongoException if the operation failed
* @mongodb.driver.manual reference/command/dropDatabase/ Drop Database
*/
public void dropDatabase() {
try {
getExecutor().execute(new DropDatabaseOperation(getName(), getWriteConcern()), getReadConcern());
} catch (MongoWriteConcernException e) {
throw createWriteConcernException(e);
}
}
/**
* Returns the name of this database.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Returns a set containing the names of all collections in this database.
*
* @return the names of collections in this database
* @throws MongoException if the operation failed
* @mongodb.driver.manual reference/method/db.getCollectionNames/ getCollectionNames()
*/
public Set getCollectionNames() {
List collectionNames =
new MongoIterableImpl(null, executor, ReadConcern.DEFAULT, primary(),
mongo.getMongoClientOptions().getRetryReads()) {
@Override
public ReadOperation> asReadOperation() {
return new ListCollectionsOperation<>(name, commandCodec)
.nameOnly(true);
}
}.map(result -> (String) result.get("name")).into(new ArrayList<>());
Collections.sort(collectionNames);
return new LinkedHashSet<>(collectionNames);
}
/**
* Creates a collection with a given name and options. If the collection already exists,
* this throws a {@code CommandFailureException}.
*
* Possible options:
*
* - capped ({@code boolean}) - Enables a collection cap. False by default. If enabled,
* you must specify a size parameter.
* - size ({@code int}) - If capped is true, size specifies a maximum size in bytes for the capped collection. When
* capped is false, you may use size to preallocate space.
* - max ({@code int}) - Optional. Specifies a maximum "cap" in number of documents for capped collections. You must
* also specify size when specifying max.
*
* Note that if the {@code options} parameter is {@code null}, the creation will be deferred to when the collection is written
* to.
*
* @param collectionName the name of the collection to return
* @param options options
* @return the collection
* @throws MongoCommandException if the server is unable to create the collection
* @throws WriteConcernException if the {@code WriteConcern} specified on this {@code DB} could not be satisfied
* @throws MongoException for all other failures
* @mongodb.driver.manual reference/method/db.createCollection/ createCollection()
*/
public DBCollection createCollection(final String collectionName, @Nullable final DBObject options) {
if (options != null) {
try {
executor.execute(getCreateCollectionOperation(collectionName, options), getReadConcern());
} catch (MongoWriteConcernException e) {
throw createWriteConcernException(e);
}
}
return getCollection(collectionName);
}
/**
* Creates a view with the given name, backing collection/view name, and aggregation pipeline that defines the view.
*
* @param viewName the name of the view to create
* @param viewOn the backing collection/view for the view
* @param pipeline the pipeline that defines the view
* @return the view as a DBCollection
* @throws MongoCommandException if the server is unable to create the collection
* @throws WriteConcernException if the {@code WriteConcern} specified on this {@code DB} could not be satisfied
* @throws MongoException for all other failures
* @since 3.4
* @mongodb.server.release 3.4
* @mongodb.driver.manual reference/command/create Create Command
*/
public DBCollection createView(final String viewName, final String viewOn, final List extends DBObject> pipeline) {
return createView(viewName, viewOn, pipeline, new DBCreateViewOptions());
}
/**
* Creates a view with the given name, backing collection/view name, aggregation pipeline, and options that defines the view.
*
* @param viewName the name of the view to create
* @param viewOn the backing collection/view for the view
* @param pipeline the pipeline that defines the view
* @param options the options for creating the view
* @return the view as a DBCollection
* @throws MongoCommandException if the server is unable to create the collection
* @throws WriteConcernException if the {@code WriteConcern} specified on this {@code DB} could not be satisfied
* @throws MongoException for all other failures
* @since 3.4
* @mongodb.server.release 3.4
* @mongodb.driver.manual reference/command/create Create Command
*/
public DBCollection createView(final String viewName, final String viewOn, final List extends DBObject> pipeline,
final DBCreateViewOptions options) {
try {
notNull("options", options);
DBCollection view = getCollection(viewName);
executor.execute(new CreateViewOperation(name, viewName, viewOn, view.preparePipeline(pipeline), writeConcern)
.collation(options.getCollation()), getReadConcern());
return view;
} catch (MongoWriteConcernException e) {
throw createWriteConcernException(e);
}
}
private CreateCollectionOperation getCreateCollectionOperation(final String collectionName, final DBObject options) {
if (options.get("size") != null && !(options.get("size") instanceof Number)) {
throw new IllegalArgumentException("'size' should be Number");
}
if (options.get("max") != null && !(options.get("max") instanceof Number)) {
throw new IllegalArgumentException("'max' should be Number");
}
if (options.get("capped") != null && !(options.get("capped") instanceof Boolean)) {
throw new IllegalArgumentException("'capped' should be Boolean");
}
if (options.get("autoIndexId") != null && !(options.get("autoIndexId") instanceof Boolean)) {
throw new IllegalArgumentException("'autoIndexId' should be Boolean");
}
if (options.get("storageEngine") != null && !(options.get("storageEngine") instanceof DBObject)) {
throw new IllegalArgumentException("'storageEngine' should be DBObject");
}
if (options.get("indexOptionDefaults") != null && !(options.get("indexOptionDefaults") instanceof DBObject)) {
throw new IllegalArgumentException("'indexOptionDefaults' should be DBObject");
}
if (options.get("validator") != null && !(options.get("validator") instanceof DBObject)) {
throw new IllegalArgumentException("'validator' should be DBObject");
}
if (options.get("validationLevel") != null && !(options.get("validationLevel") instanceof String)) {
throw new IllegalArgumentException("'validationLevel' should be String");
}
if (options.get("validationAction") != null && !(options.get("validationAction") instanceof String)) {
throw new IllegalArgumentException("'validationAction' should be String");
}
boolean capped = false;
boolean autoIndex = true;
long sizeInBytes = 0;
long maxDocuments = 0;
BsonDocument storageEngineOptions = null;
BsonDocument indexOptionDefaults = null;
BsonDocument validator = null;
ValidationLevel validationLevel = null;
ValidationAction validationAction = null;
if (options.get("capped") != null) {
capped = (Boolean) options.get("capped");
}
if (options.get("size") != null) {
sizeInBytes = ((Number) options.get("size")).longValue();
}
if (options.get("autoIndexId") != null) {
autoIndex = (Boolean) options.get("autoIndexId");
}
if (options.get("max") != null) {
maxDocuments = ((Number) options.get("max")).longValue();
}
if (options.get("storageEngine") != null) {
storageEngineOptions = wrap((DBObject) options.get("storageEngine"));
}
if (options.get("indexOptionDefaults") != null) {
indexOptionDefaults = wrap((DBObject) options.get("indexOptionDefaults"));
}
if (options.get("validator") != null) {
validator = wrap((DBObject) options.get("validator"));
}
if (options.get("validationLevel") != null) {
validationLevel = ValidationLevel.fromString((String) options.get("validationLevel"));
}
if (options.get("validationAction") != null) {
validationAction = ValidationAction.fromString((String) options.get("validationAction"));
}
Collation collation = DBObjectCollationHelper.createCollationFromOptions(options);
return new CreateCollectionOperation(getName(), collectionName, getWriteConcern())
.capped(capped)
.collation(collation)
.sizeInBytes(sizeInBytes)
.autoIndex(autoIndex)
.maxDocuments(maxDocuments)
.storageEngineOptions(storageEngineOptions)
.indexOptionDefaults(indexOptionDefaults)
.validator(validator)
.validationLevel(validationLevel)
.validationAction(validationAction);
}
/**
* Executes a database command. This method constructs a simple DBObject using {@code command} as the field name and {@code true} as its
* value, and calls {@link DB#command(DBObject, ReadPreference) } with the default read preference for the database.
*
* @param command command to execute
* @return result of command from the database
* @throws MongoException if the command failed
* @mongodb.driver.manual tutorial/use-database-commands Commands
*/
public CommandResult command(final String command) {
return command(new BasicDBObject(command, Boolean.TRUE), getReadPreference());
}
/**
* Executes a database command. This method calls {@link DB#command(DBObject, ReadPreference) } with the default read preference for the
* database.
*
* @param command {@code DBObject} representation of the command to be executed
* @return result of the command execution
* @throws MongoException if the command failed
* @mongodb.driver.manual tutorial/use-database-commands Commands
*/
public CommandResult command(final DBObject command) {
return command(command, getReadPreference());
}
/**
* Executes a database command. This method calls {@link DB#command(DBObject, ReadPreference, DBEncoder) } with the default read
* preference for the database.
*
* @param command {@code DBObject} representation of the command to be executed
* @param encoder {@link DBEncoder} to be used for command encoding
* @return result of the command execution
* @throws MongoException if the command failed
* @mongodb.driver.manual tutorial/use-database-commands Commands
*/
public CommandResult command(final DBObject command, final DBEncoder encoder) {
return command(command, getReadPreference(), encoder);
}
/**
* Executes a database command with the selected readPreference, and encodes the command using the given encoder.
*
* @param command The {@code DBObject} representation the command to be executed
* @param readPreference Where to execute the command - this will only be applied for a subset of commands
* @param encoder The DBEncoder that knows how to serialise the command
* @return The result of executing the command, success or failure
* @mongodb.driver.manual tutorial/use-database-commands Commands
* @since 2.12
*/
public CommandResult command(final DBObject command, final ReadPreference readPreference, @Nullable final DBEncoder encoder) {
try {
return executeCommand(wrap(command, encoder), getCommandReadPreference(command, readPreference));
} catch (MongoCommandException ex) {
return new CommandResult(ex.getResponse(), getDefaultDBObjectCodec(), ex.getServerAddress());
}
}
/**
* Executes the command against the database with the given read preference.
*
* @param command The {@code DBObject} representation the command to be executed
* @param readPreference Where to execute the command - this will only be applied for a subset of commands
* @return The result of executing the command, success or failure
* @mongodb.driver.manual tutorial/use-database-commands Commands
* @since 2.12
*/
public CommandResult command(final DBObject command, final ReadPreference readPreference) {
return command(command, readPreference, null);
}
/**
* Executes a database command. This method constructs a simple {@link DBObject} and calls {@link DB#command(DBObject, ReadPreference)
* }.
*
* @param command The name of the command to be executed
* @param readPreference Where to execute the command - this will only be applied for a subset of commands
* @return The result of the command execution
* @throws MongoException if the command failed
* @mongodb.driver.manual tutorial/use-database-commands Commands
* @since 2.12
*/
public CommandResult command(final String command, final ReadPreference readPreference) {
return command(new BasicDBObject(command, true), readPreference);
}
/**
* Gets another database on same server
*
* @param name name of the database
* @return the DB for the given name
*/
@SuppressWarnings("deprecation") // The old API (i.e. DB) will use deprecated methods.
public DB getSisterDB(final String name) {
return mongo.getDB(name);
}
/**
* Checks to see if a collection with a given name exists on a server.
*
* @param collectionName a name of the collection to test for existence
* @return {@code false} if no collection by that name exists, {@code true} if a match to an existing collection was found
* @throws MongoException if the operation failed
*/
public boolean collectionExists(final String collectionName) {
Set collectionNames = getCollectionNames();
for (final String name : collectionNames) {
if (name.equalsIgnoreCase(collectionName)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "DB{name='" + name + '\'' + '}';
}
CommandResult executeCommand(final BsonDocument commandDocument, final ReadPreference readPreference) {
return new CommandResult(executor.execute(new CommandReadOperation<>(getName(), commandDocument,
new BsonDocumentCodec()), readPreference, getReadConcern()), getDefaultDBObjectCodec());
}
OperationExecutor getExecutor() {
return executor;
}
private BsonDocument wrap(final DBObject document) {
return new BsonDocumentWrapper<>(document, commandCodec);
}
private BsonDocument wrap(final DBObject document, @Nullable final DBEncoder encoder) {
if (encoder == null) {
return wrap(document);
} else {
return new BsonDocumentWrapper<>(document, new DBEncoderAdapter(encoder));
}
}
/**
* Determines the read preference that should be used for the given command.
*
* @param command the {@link DBObject} representing the command
* @param requestedPreference the preference requested by the client.
* @return the read preference to use for the given command. It will never return {@code null}.
* @see com.mongodb.ReadPreference
*/
ReadPreference getCommandReadPreference(final DBObject command, @Nullable final ReadPreference requestedPreference) {
String comString = command.keySet().iterator().next().toLowerCase();
boolean primaryRequired = !OBEDIENT_COMMANDS.contains(comString);
if (primaryRequired) {
return primary();
} else if (requestedPreference == null) {
return primary();
} else {
return requestedPreference;
}
}
Codec getDefaultDBObjectCodec() {
return new DBObjectCodec(getMongoClient().getCodecRegistry(),
DBObjectCodec.getDefaultBsonTypeClassMap(),
new DBCollectionObjectFactory())
.withUuidRepresentation(getMongoClient().getMongoClientOptions().getUuidRepresentation());
}
private static final Set OBEDIENT_COMMANDS = new HashSet<>();
static {
OBEDIENT_COMMANDS.add("aggregate");
OBEDIENT_COMMANDS.add("collstats");
OBEDIENT_COMMANDS.add("count");
OBEDIENT_COMMANDS.add("dbstats");
OBEDIENT_COMMANDS.add("distinct");
OBEDIENT_COMMANDS.add("geonear");
OBEDIENT_COMMANDS.add("geosearch");
OBEDIENT_COMMANDS.add("geowalk");
OBEDIENT_COMMANDS.add("group");
OBEDIENT_COMMANDS.add("listcollections");
OBEDIENT_COMMANDS.add("listindexes");
OBEDIENT_COMMANDS.add("parallelcollectionscan");
OBEDIENT_COMMANDS.add("text");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy