Check if mongodb database exists? - mongodb

Is there a possibility to check if a mongo database allready exists?

Yes, you can get the list of existing databases. From the Java driver you could do something like this to get the database names on a mongod server running on localhost
Mongo mongo = new Mongo( "127.0.0.1", 27017 );
List<String> databaseNames = mongo.getDatabaseNames();
This is equivalent to the mongo shell "show dbs" command. I am sure similar methods exist in all of the drivers.

From the shell, if you want to explicitely check that a DB exists:
db.getMongo().getDBNames().indexOf("mydb");
Will return '-1' if "mydb" does not exist.
To use this from the shell:
if [ $(mongo localhost:27017 --eval 'db.getMongo().getDBNames().indexOf("mydb")' --quiet) -lt 0 ]; then
echo "mydb does not exist"
else
echo "mydb exists"
fi

For anyone who comes here because the method getDatabaseNames(); is depreciated / not available, here is the new way to get the list of existing databases:
MongoClient mongoClient = new MongoClient();
MongoCursor<String> dbsCursor = mongoClient.listDatabaseNames().iterator();
while(dbsCursor.hasNext()) {
System.out.println(dbsCursor.next());
}
Here is a method that validates if the database is found:
public Boolean databaseFound(String databaseName){
MongoClient mongoClient = new MongoClient(); //Maybe replace it with an already existing client
MongoCursor<String> dbsCursor = mongoClient.listDatabaseNames().iterator();
while(dbsCursor.hasNext()) {
if(dbsCursor.next().equals(databaseName))
return true;
}
return false;
}

in python using Pymongo
from pymongo import MongoClient
db_name = "foo"
conn = MongoClient('mongodb://localhost,localhost:27017')
db = self.conn[str(db_name)]
if bool(db_name in conn.database_names()):
collection.drop()

using MongoDb c# Driver 2.4
private bool DatabaseExists(string database)
{
// _client is IMongoClient
var dbList = _client.ListDatabases().ToList().Select(db => db.GetValue("name").AsString);
return dbList.Contains(database);
}
usage:
if (!DatabaseExists("FooDb")
{
// create and seed db
}

I'd like to add a C# version. I'm using the MongoDB.Driver 2.2.2.
static bool DatabaseExists(string connectionString)
{
var mongoUri = new MongoUrl(connectionString);
var client = new MongoClient(mongoUri);
var dbList = Enumerate(client.ListDatabases()).Select(db => db.GetValue("name").AsString);
return dbList.Contains(mongoUri.DatabaseName);
}
static IEnumerable<BsonDocument> Enumerate(IAsyncCursor<BsonDocument> docs)
{
while (docs.MoveNext())
{
foreach (var item in docs.Current)
{
yield return item;
}
}
}

Try this, it worked for me (on Mac OSx)
MongoClient mongoClient = new MongoClient("localhost");
/** **/
boolean dbExist =
mongoClient.listDatabaseNames().
into(new ArrayList<String>()).contains("TEST");
System.out.print(dbExist);

The PyMongo example above didn't work for me, so I rewrote it using the more standard list_databases() method to the MongoClient library:
from pymongo import MongoClient
db_name = "foo"
conn = MongoClient('mongodb://localhost,localhost:27017')
if bool(db_name in conn.list_databases()):
print true # or return true here
else:
print false # or return false here

In my case, I could not use listDatabaseNames, because my user did not have the rights to call this function. Instead, I just assume that it exists and call a method on this database, which will fail if it does not exist or if rights are missing.
Demo C# code:
/// <summary>
/// Tests the connection to the MongoDB server, and if the database already exists.
/// If not or an error is detected, an exception is thrown.
/// </summary>
public static void TestConnection(string mongoUrl, string mongoDatabase) {
var client = new MongoClient(mongoUrl);
var database = client.GetDatabase(mongoDatabase);
try {
// Try to perform an action on this database; will fail if it does not exist
database.ListCollections();
}
catch {
throw new Exception("Connection established, " +
"but database does not exist (or missing rights): " + mongoDatabase);
}
}

I searched for how to list database names in golang and accidentially found this page. Looks like no one has provided ways to check if specific database name exists.
Assume that you are using MongoDB Go Driver, here is an approach
// client type is *mongo.Client
dbNames, err := client.ListDatabaseNames(context.Background(), bson.D{{Key: "name", Value: "YOUR-DB-NAME"}})
"dbNames" contains list of all databases in mongo server.
Second parameter is a filter, in this case, it only allows database with name == "YOUR-DB-NAME". Thus, dbNames will be empty if "YOUR-DB-NAME" is not exist.

Related

Cannot query dockerized MongoDB container from dockerized ASP.NET Core 3.1 container

I have a dockerized .net core container and am trying to query a MongoDB database. I have a REST API that is called to query the database from the .net core container. It seems as if I am able to establish a connection to the container when the instance of the service is created:
private readonly IMongoCollection<DbObject> _dbObjects;
public TaxService(IDbConfig dbConfig)
{
Console.Out.WriteLine("got here: " + dbConfig.ConnectionString);
MongoClient client = new MongoClient(dbConfig.ConnectionString);
IMongoDatabase database = client.GetDatabase(dbConfig.DatabaseName);
_dbObjects = database.GetCollection<DbObject>(dbConfig.SalesTaxCollectionName);
Console.Out.WriteLine("db initialized");
}
Here is the dbConfig object:
"DbConfig": {
"SalesTaxCollectionName": "ExampleCollection",
"ConnectionString": "mongodb://mongo:27017",
"DatabaseName": "ExampleDb"
}
It gets through this code, but when the database is actually queried, a PlatformNotSupportedException is thrown:
public DbObject GetByValue(string value)
{
Console.Out.WriteLine("querying db");
List<DbObject> matches = _dbObjects.Find(dbObject => dbObject.Value.Equals(value)).ToList();
Console.Out.WriteLine("successfully queried"); // Does not reach this point
if (matches.Any())
{
return matches.First();
}
else
{
throw new ArgumentException($"No values matched");
}
}
I have put the rest of the files in gists for convenience:
docker-compose.yml: https://gist.github.com/MinhazMurks/1fbb47afd360bbac48df45b1f0609e33
Dockerfile: https://gist.github.com/MinhazMurks/bb2b7f76d28894a81136d940b5997165
InitExampleDb.js: https://gist.github.com/MinhazMurks/9aae03daceee1e689c4e821419966f41
Full-Log: https://gist.github.com/MinhazMurks/0de9cd822fcf2930065527191127c83b
Any insight would be appreciated!
You can try to set the following line in the host file:
(It is located here in case of Windows: C:\Windows\System32\drivers\etc\hosts)
127.0.0.1 mongo
After this try connect using RoboMongo. In the Address textbox insert mongo and try to connect to it.

MongoDB options in connection string are being interpreted as the database name

I am trying to set the maxPoolSize via connection string in MongoDB following this piece of documentation. Here is my connection string:
mongodb://localhost:27017/databaseName?maxPoolSize=200
However, instead of having the database databaseName with the maxPoolSize equals to 200, I'm getting a database called databaseName?maxPoolSize=200. This is, Mongo is getting everything (name + options) as the database name.
Some info:
Mongo version: 3.2.10
Connecting using Morphia 1.1.0
I will be happy to provide any further information.
if you are doing
MongoClient client = new MongoClient(
"mongodb://localhost:27017/databaseName?maxPoolSize=200");
then dont do that, instead do as following,
MongoClient client = new MongoClient(
new MongoClientURI(
"mongodb://localhost:27017/databaseName?maxPoolSize=200"));
because you need to tell mongo that you are passing some options along the connection string.
if you think i misunderstood your question. please post the piece of code where you are trying to get a connection.
You can try something like this.
MongoClientURI uri = new MongoClientURI("mongodb://localhost:27017/databaseName?maxPoolSize=200");
MongoClient mongoClient = new MongoClient(uri);
Morphia morphia = new Morphia();
Datastore datastore = morphia.createDatastore(mongoClient, "dbname");
Alternatively
MongoClientOptions.Builder options = new MongoClientOptions.Builder();
//set your connection option here.
options.connectionsPerHost(200); //max pool size
MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017), options.build());
Morphia morphia = new Morphia();
Datastore datastore = morphia.createDatastore(mongoClient, "dbname");

Cannot attach database file when using Entity Framework Core Migration commands

I am using EntityFramework Core commands to migration database. The command I am using is like the docs suggests: dnx . ef migration apply. The problem is when specifying AttachDbFileName in connection string, the following error appear: Unable to Attach database file as database xxxxxxx. This is the connection string I am using:
Data Source=(LocalDB)\mssqllocaldb;Integrated Security=True;Initial Catalog=EfGetStarted2;AttachDbFileName=D:\EfGetStarted2.mdf
Please help how to attach the db file to another location.
Thanks
EF core seem to have troubles with AttachDbFileName or doesn't handle it at all.
EnsureDeleted changes the database name to master but keeps any AttachDbFileName value, which leads to an error since we cannot attach the master database to another file.
EnsureCreated opens a connection using the provided AttachDbFileName value, which leads to an error since the file of the database we want to create does not yet exist.
EF6 has some logic to handle these use cases, see SqlProviderServices.DbCreateDatabase, so everything worked quite fine.
As a workaround I wrote some hacky code to handle these scenarios:
public static void EnsureDatabase(this DbContext context, bool reset = false)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (reset)
{
try
{
context.Database.EnsureDeleted();
}
catch (SqlException ex) when (ex.Number == 1801)
{
// HACK: EF doesn't interpret error 1801 as already existing database
ExecuteStatement(context, BuildDropStatement);
}
catch (SqlException ex) when (ex.Number == 1832)
{
// nothing to do here (see below)
}
}
try
{
context.Database.EnsureCreated();
}
catch (SqlException ex) when (ex.Number == 1832)
{
// HACK: EF doesn't interpret error 1832 as non existing database
ExecuteStatement(context, BuildCreateStatement);
// this takes some time (?)
WaitDatabaseCreated(context);
// re-ensure create for tables and stuff
context.Database.EnsureCreated();
}
}
private static void WaitDatabaseCreated(DbContext context)
{
var timeout = DateTime.UtcNow + TimeSpan.FromMinutes(1);
while (true)
{
try
{
context.Database.OpenConnection();
context.Database.CloseConnection();
}
catch (SqlException)
{
if (DateTime.UtcNow > timeout)
throw;
continue;
}
break;
}
}
private static void ExecuteStatement(DbContext context, Func<SqlConnectionStringBuilder, string> statement)
{
var builder = new SqlConnectionStringBuilder(context.Database.GetDbConnection().ConnectionString);
using (var connection = new SqlConnection($"Data Source={builder.DataSource}"))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = statement(builder);
command.ExecuteNonQuery();
}
}
}
private static string BuildDropStatement(SqlConnectionStringBuilder builder)
{
var database = builder.InitialCatalog;
return $"drop database [{database}]";
}
private static string BuildCreateStatement(SqlConnectionStringBuilder builder)
{
var database = builder.InitialCatalog;
var datafile = builder.AttachDBFilename;
var dataname = Path.GetFileNameWithoutExtension(datafile);
var logfile = Path.ChangeExtension(datafile, ".ldf");
var logname = dataname + "_log";
return $"create database [{database}] on primary (name = '{dataname}', filename = '{datafile}') log on (name = '{logname}', filename = '{logfile}')";
}
It's far from nice, but I'm using it for integration testing anyway. For "real world" scenarios using EF migrations should be the way to go, but maybe the root cause of this issue is the same...
Update
The next version will include support for AttachDBFilename.
There may be a different *.mdf file already attached to a database named EfGetStarted2... Try dropping/detaching that database then try again.
You might also be running into problems if the user LocalDB is running as doesn't have correct permissions to the path.

At what point does the MongoDB C# driver open a connection?

I'm having a problem with lots of connections being opened to the mongo db.
The readme on the Github page for the C# driver gives the following code:
using MongoDB.Bson;
using MongoDB.Driver;
var client = new MongoClient("mongodb://localhost:27017");
var server = client.GetServer();
var database = server.GetDatabase("foo");
var collection = database.GetCollection("bar");
collection.Insert(new BsonDocument("Name", "Jack"));
foreach(var document in collection.FindAll())
{
Console.WriteLine(document["Name"]);
}
At what point does the driver open the connection to the server? Is it at the GetServer() method or is it the Insert() method?
I know that we should have a static object for the client, but should we also have a static object for the server and database as well?
Late answer... but the server connection is created at this point:
var client = new MongoClient("mongodb://localhost:27017");
Everything else is just getting references for various objects.
See: http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-csharp-driver/
While using the latest MongoDB drivers for C#, the connection happens at the actual database operation. For eg. db.Collection.Find() or at db.collection.InsertOne().
{
//code for initialization
//for localhost connection there is no need to specify the db server url and port.
var client = new MongoClient("mongodb://localhost:27017/");
var db = client.GetDatabase("TestDb");
Collection = db.GetCollection<T>("testCollection");
}
//Code for db operations
{
//The connection happens here.
var collection = db.Collection;
//Your find operation
var model = collection.Find(Builders<Model>.Filter.Empty).ToList();
//Your insert operation
collection.InsertOne(Model);
}
I found this out after I stopped my mongod server and debugged the code with breakpoint. Initialization happened smoothly but error was thrown at db operation.
Hope this helps.

MongoDB connection over SSL in Play Framework

I am using Play 1.2.5, MongoDB and Morphia module 1.2.9 in my application.
To create a secure and encrypted connection to the db, I installed MongoDB by enabling SSL using the follwoing links
http://docs.mongodb.org/manual/administration/ssl/
http://www.mongodb.org/about/tutorial/build-mongodb-on-linux/
Now I'm able to connect to the mongo shell using mongo --ssl also able to verify whether MongoDB is running or not using https://mylocalhost.com:27017/
But after enabling SSL in MongoDB, I am not able to connect to it through my play application.
Following are the lines I used in the application.conf to connect to the db
morphia.db.host=localhost
morphia.db.port=27017
morphia.db.db=test
Is there any configurations available to connect over SSL?
I did some googling and I am not able to find any solutions. Please help me over this?
Thanks in advance.
Morphia module does not support ssl connection for the moment. And I am not sure morphia library support it. Please create an issue on github to track this requirement: https://github.com/greenlaw110/play-morphia/issues?state=open
I use spring-data and came up against the same issue. With spring-data i was able to construct a Mongo object myself and passes it as a constructor param. Morphia might have the same mechanism. The key is:
options.socketFactory = SSLSocketFactory.getDefault();
After that, make sure you install the SSL public key into your key store and it should work.
public class MongoFactory {
public Mongo buildMongo (String replicaSet, boolean slaveOk, int writeNumber , int connectionsPerHost, boolean useSSL) throws UnknownHostException{
ServerAddress addr = new ServerAddress();
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
int port =0;
String host = new String();
if ( replicaSet == null )
throw new UnknownHostException("Please provide hostname");
replicaSet = replicaSet.trim();
if ( replicaSet.length() == 0 )
throw new UnknownHostException("Please provide hostname");
StringTokenizer tokens = new StringTokenizer(replicaSet, ",");
while(tokens.hasMoreTokens()){
String token = tokens.nextToken();
int idx = token.indexOf( ":" );
if ( idx > 0 ){
port = Integer.parseInt( token.substring( idx + 1 ) );
host = token.substring( 0 , idx ).trim();
}
addr = new ServerAddress(host.trim(), port);
addresses.add(addr);
}
MongoOptions options = new MongoOptions();
options.autoConnectRetry = true;
if (useSSL){
options.socketFactory = SSLSocketFactory.getDefault();
}
options.connectionsPerHost=connectionsPerHost;
options.w=writeNumber;
options.fsync=false;
options.wtimeout=5000;
options.connectTimeout=5000;
options.autoConnectRetry=true;
options.socketKeepAlive=true;
Mongo m = new Mongo(addresses, options);
if(slaveOk){
m.setReadPreference(ReadPreference.SECONDARY);
}
return m;
}
}