MongoDB: Getting the list of all databases? - mongodb

How do I list all databases for a connection using Mongo C# Driver?

Very easily:
var server = MongoServer.Create("mongodb://localhost/?safe=true");
var databaseNames = server.GetDatabaseNames();

The MongoServer class was deprecated in version 2.0.0.
You can use ListDatabasesAsync
using (var cursor = await client.ListDatabasesAsync())
{
await cursor.ForEachAsync(d => Console.WriteLine(d.ToString()));
}

Working Solution:
MongoClient client = new MongoClient("mongodb://localhost:27017");
using (IAsyncCursor<BsonDocument> cursor = client.ListDatabases())
{
while (cursor.MoveNext())
{
foreach (var doc in cursor.Current)
{
Console.WriteLine(doc["name"]); // database name
}
}
}

The MongoServer class was deprecated in version 2.0.0 as Juri pointed out. If you don't want to use async, here's how I do it:
var client = new MongoClient("mongodb://" + server_username + ":" + server_password + "#" + server_host + ":" + server_port);
List<MongoDB.Bson.BsonDocument> databases = client.ListDatabases();
Just one thing. It is in BsonDocument format that has 2 elements: "name" and "sizeOnDisk".
Hope this helps.

I wasn't able validate if a given DB exists or not with the existing answers, so here's my take on it:
// extension method on IMongoClient
public static IMongoClient AssertDbExists(this IMongoClient client, string dbName)
{
bool dbFound = false;
using(var cursor = client.ListDatabases())
{
var databaseDocuments = cursor.ToList();
foreach (var db in databaseDocuments)
{
if (db["name"].ToString().Equals(dbName))
{
dbFound = true;
break;
}
}
}
if (!dbFound) throw new ArgumentException("Can't connect to a specific database with the information provided", nameof(MongoSettings.ConnectionString));
return client;
}
And then use it like this:
// either you get the client with the DB validated or throws
_client = new MongoClient(settings.ConnectionString).AssertDbExists(_dbName);
Using: Mongo Official C# driver v2.4.4

Related

Upgrade to CSLA 6: ConnectionManager problem

we are trying to upgrade to CSLA 6.
now, we are getting a message:
"ConnectionManager is obsolete, use dependency injection ... use ApplicationContext.LocalContext"
for this code:
using (var ctx = ConnectionManager<OracleConnection>.GetManager("dbEndpoint", true))
We've tried this code snippet but all connections is NULL.
Could you please help us to correctly get Connection?
var services = new ServiceCollection();
services.AddCsla();
var provider = services.BuildServiceProvider();
DataPortalFactory = provider.GetRequiredService<IDataPortalFactory>();
var appContext = provider.GetRequiredService<Csla.ApplicationContext>();
var conn1 = appContext.LocalContext.GetValueOrNull("dbEndpoint");
var conn2 = appContext.LocalContext.GetValueOrNull("__db:default-dbEndpoint");
var conn3 = appContext.LocalContext["dbEndpoint"];
var conn4 = appContext.LocalContext["__db:default-dbEndpoint"];
another experiment:
....
var CONNECTION_ORACLE = new OracleConnection(ConfigurationManager.ConnectionStrings["dbEndpoint"].ConnectionString);
services.AddScoped<IDbConnection>(o => CONNECTION_ORACLE);
....
var provider = services.BuildServiceProvider();
...
var connectionResolved = provider.GetRequiredService<IDbConnection>();
appContext.LocalContext.Add("dbEndpoint", connectionResolved);
then connection is not null;
and inside of Factory is successfully resolved by DI:
public DocFactory(ApplicationContext appContext, IDbConnection connection) : base(
appContext)
{
_connection = connection;
}
then
[Fetch]
public Doc_Fetch(DocCriteria criteria)
{
bool cancel = false;
OnFetching(criteria, ref cancel);
if (cancel) return null;
Doc item = null;
OracleConnection connection = _connection as OracleConnection;
connection is Closed (but NOT null!!). it's possible to open it but if close it, somebody else consuming it will face with a problem or child objects also will face problem with closed connection.
so, making ConnectionManager as Obsolete may be not so obvious way to go. But ConnectionManager was very useful for counting open connection, supporting transactions etc
Could you please provide a workaround for it.
more attempts:
var connectionString =
ConfigurationManager.ConnectionStrings["dbEndpoint"].ConnectionString;
..
appContext.ClientContext.Add("DBConnectionString", connectionString );
...
Factory
using (var connection = new OracleConnection(ApplicationContext.ClientContext["DBConnectionString"].ToString()))
{
connection.Open();
Your DAL should require that a database connection be injected.
public class MyDal : IDisposable
{
public MyDal(OracleConnection connection)
{
Connection = connection;
}
private OracleConnection Connection { get; set; }
public MyData GetData()
{
// use Connection to get the data
return data;
}
public void Dispose()
{
Connection.Dispose();
}
}
Then in the app server startup code, register your DAL type(s) and also register your connection type.
services.AddScoped(typeof(OracleConnection), () =>
{
// initialize the connection here
return connection;
});
services.AddScoped<MyDal>();
Then, in your data portal operation method (such as create, fetch, etc.), inject your DAL:
[Fetch]
private void Fetch([Inject] MyDal dal)
{
var data = dal.GetData();
}

MongoDB: Using $sample with C# driver

I'm trying to express the following query using the MongoDB C# driver (2.4.4):
db.media.aggregate({ $sample: { size: 1 }})
This what I have so far:
BsonDocument sample = new BsonDocument
{
{ "$sample", new BsonDocument { { "size", 1 } } }
};
MongoBlob mongoBlob = await _collection
.Aggregate()
.Group<MongoBlob>(sample)
.FirstOrDefaultAsync();
I cannot put the sample to .Aggregate(AggregateOptions options = null) and putting it into the .Group(...) is obviously wrong. There is also no any like a .Sample() method.
Please, help. Thank you in advance.
Simply,
var randEl = await collection.AsQueryable().Sample(1).FirstOrDefaultAsync();
Do not forget add
using MongoDB.Driver.Linq;
I believe it should be
MongoBlob mongoBlob = await _collection
.Aggregate()
.Sample(1)
.FirstOrDefaultAsync();
If this doesn't work then let me know. Don't have windows system up right now to confirm
Edit (7-AUG):
Turns out its not that simple. The sample method doesn't exists in current driver. The classes which handle this are internal so no straight forward way to inherit. So worked out a solution based on reflection and a hack. Where you add a Stage to the pipeline and then edit it through reflection. Below is a working sample of my demo code
using System;
using MongoDB.Bson;
using MongoDB.Driver;
using System.Reflection;
namespace TestMongo
{
public static class MainClass
{
static IMongoClient _client;
static IMongoDatabase _database;
public static IAggregateFluent<BsonDocument> Sample(this IAggregateFluent<BsonDocument> agg, int count){
var new_agg = agg.Skip(10);
var stage =new_agg.Stages[new_agg.Stages.Count-1];
var newDoc = new BsonDocument {
{ "$sample", new BsonDocument {
{"size", count}
} }
};
stage.GetType().GetField("_document"
, BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(stage, newDoc);
return new_agg;
}
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
_client = new MongoClient();
_database = _client.GetDatabase("jobs");
var col = _database.GetCollection<BsonDocument>("results");
var agg = col.Aggregate().Sample(1);
var data = agg.FirstOrDefault();
data = null;
}
}
}
var sample = new BsonDocument
{
{
"$sample", new BsonDocument
{
{"size", 1000}
}
}
};
var samples = _collection.Aggregate().AppendStage(new BsonDocumentPipelineStageDefinition<MyType, MyType>(sample));
return await samples.ToListAsync();

Update the subDcoument attribute

I have a document having schema like bellow
{
"Personal":[
{
"name":"Test_Name",
"isActive":true
}
]
}
am trying to update this as below using java driver.
collections.updateMany(new Document("Personal.name", "Test_Name"), new Document("$set", new Document("Personal.$.isActive", false)))
But unfortunately this trows an error
"The positional operator did not find the match needed from the query. Unexpanded update: Personal.$.isActive"
But if i modify the above update filter something like
collections.updateMany(new Document("Personal.name", "Test_Name"), new Document("$set", new Document("Personal.0.isActive", false)))
it works.
Can any one help me in understanding whats wrong in using "$" in my 1st update statement?
Here is some more code spinets
Creating the collection object:
collections = mongoConnection.establishConnection()
MongoConnection object:
public MongoConnection() {
StringBuilder connectionString = new StringBuilder();
connectionString.append("mongodb://url_with_port_and_server")
client = new MongoClient(new MongoClientURI(connectionString.toString()));
db = client.getDatabase("test");
collections = db.getCollection("test");
}
public MongoCollection<Document> establishConnection() {
return collections;
}
public void closeConnection() {
client.close();
}

RuntimeBinderException: Convert type System.Threading.Tasks.Task<object> to string

I do an example with signalR. But it doesn't function because of one mistake.
The one mistake (can not convert type system.threading.tasks.task< object> to string) is in this line:
return context.Clients.All.RecieveNotification(simple);
It is at the bottom of the code you can see below.
Below you see the method I wrote. There I do a connection with the database and get the content with a command/query.
Then a few checks and also SqlDependency.
public string SendNotifications()
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
string query = "SELECT eintrag FROM [dbo].[simple_column]";
connection.Open();
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Notification = null;
DataTable dt = new DataTable();
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
dt.Load(reader);
if (dt.Rows.Count > 0)
{
simple = dt.Rows[0]["eintrag"].ToString();
}
}
}
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
return context.Clients.All.RecieveNotification(simple);
}
And here I use the function:
var notifications = $.connection.notificationHub;
notifications.client.recieveNotification = function (simple) {
// Add the message to the page.
$('#dbMessage').text(simple);
};
I hope you can help me.
Thanks.

SMO: restoring to a different DB

I've read a dozen different blogs, as well as reading through the msdn examples and they just aren't working for me.
Ultimately what I'm trying to do is automate moving a DB from our production instance to our dev instance, or the other direction.
The approach I've taken is thus:
backup/restore to a temp DB
detach temp DB
copy mdf and ldf files to the other instance
reattach.
I'm stuck on 1 and I cannot understand why. Everything I've read claims this should be working.
NOTE: I've set dbName to the db I want to restore to. I have also set restore.Database = dbName, where restore is an instance of the Restore class in the smo namespace.
mdf.LogicalFileName = dbName;
mdf.PhysicalFileName = String.Format(#"{0}\{1}.mdf", server.Information.MasterDBPath, dbName);
ldf.LogicalFileName = dbName + "_log";
ldf.PhysicalFileName = String.Format(#"{0}\{1}.ldf", server.Information.MasterDBPath, dbName);
restore.RelocateFiles.Add(mdf);
restore.RelocateFiles.Add(ldf);
restore.SqlRestore(server);
This is the exception I'm getting:
The file 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.mdf' cannot be overwritten. It is being used by database 'MIQDesignTest2'.
File 'MIQDesign' cannot be restored to 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.mdf'. Use WITH MOVE to identify a valid location for the file.
The file 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.ldf' cannot be overwritten. It is being used by database 'MIQDesignTest2'.
File 'MIQDesign_log' cannot be restored to 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.ldf'. Use WITH MOVE to identify a valid location for the file.
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
RESTORE DATABASE is terminating abnormally.
Why is this trying to overwrite the original mdf? Isn't the RelocateFiles stuff supposed to specify that you want it being saved to a different physical filename?
It is works.
public class DatabaseManager
{
public Action<int, string> OnSqlBackupPercentComplete;
public Action<int, string> OnSqlRestorePercentComplete;
public Action<SqlError> OnSqlBackupComplete;
public Action<SqlError> OnSqlRestoreComplete;
public bool IsConnected { get; private set; }
private ServerConnection _connection;
public void Connect(string userName, string password, string serverName, bool useInteratedLogin)
{
if (useInteratedLogin)
{
var sqlCon = new SqlConnection(string.Format("Data Source={0}; Integrated Security=True; Connection Timeout=5", serverName));
_connection = new ServerConnection(sqlCon);
_connection.Connect();
IsConnected = true;
}
else
{
_connection = new ServerConnection(serverName, userName, password);
_connection.ConnectTimeout = 5000;
_connection.Connect();
IsConnected = true;
}
}
public void BackupDatabase(string databaseName, string destinationPath)
{
var sqlServer = new Server(_connection);
databaseName = databaseName.Replace("[", "").Replace("]", "");
var sqlBackup = new Backup
{
Action = BackupActionType.Database,
BackupSetDescription = "ArchiveDataBase:" + DateTime.Now.ToShortDateString(),
BackupSetName = "Archive",
Database = databaseName
};
var deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
sqlBackup.Initialize = true;
sqlBackup.Checksum = true;
sqlBackup.ContinueAfterError = true;
sqlBackup.Devices.Add(deviceItem);
sqlBackup.Incremental = false;
sqlBackup.ExpirationDate = DateTime.Now.AddDays(3);
sqlBackup.LogTruncation = BackupTruncateLogType.Truncate;
sqlBackup.PercentCompleteNotification = 10;
sqlBackup.PercentComplete += (sender, e) => OnSqlBackupPercentComplete(e.Percent, e.Message);
sqlBackup.Complete += (sender, e) => OnSqlBackupComplete(e.Error);
sqlBackup.FormatMedia = false;
sqlBackup.SqlBackup(sqlServer);
}
public DatabaseCollection GetDatabasesList()
{
if (IsConnected)
{
var sqlServer = new Server(_connection);
return sqlServer.Databases;
}
return null;
}
public void RestoreDatabase(string databaseName, string filePath)
{
var sqlServer = new Server(_connection);
databaseName = databaseName.Replace("[", "").Replace("]", "");
var sqlRestore = new Restore();
sqlRestore.PercentCompleteNotification = 10;
sqlRestore.PercentComplete += (sender, e) => OnSqlRestorePercentComplete(e.Percent, e.Message);
sqlRestore.Complete += (sender, e) => OnSqlRestoreComplete(e.Error);
var deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
sqlRestore.Devices.Add(deviceItem);
sqlRestore.Database = databaseName;
DataTable dtFileList = sqlRestore.ReadFileList(sqlServer);
int lastIndexOf = dtFileList.Rows[1][1].ToString().LastIndexOf(#"\");
string physicalName = dtFileList.Rows[1][1].ToString().Substring(0, lastIndexOf + 1);
string dbLogicalName = dtFileList.Rows[0][0].ToString();
string dbPhysicalName = physicalName + databaseName + ".mdf";
string logLogicalName = dtFileList.Rows[1][0].ToString();
string logPhysicalName = physicalName + databaseName + "_log.ldf";
sqlRestore.RelocateFiles.Add(new RelocateFile(dbLogicalName, dbPhysicalName));
sqlRestore.RelocateFiles.Add(new RelocateFile(logLogicalName, logPhysicalName));
sqlServer.KillAllProcesses(sqlRestore.Database);
Database db = sqlServer.Databases[databaseName];
if (db != null)
{
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
db.Alter(TerminationClause.RollbackTransactionsImmediately);
sqlServer.DetachDatabase(sqlRestore.Database, false);
}
sqlRestore.Action = RestoreActionType.Database;
sqlRestore.ReplaceDatabase = true;
sqlRestore.SqlRestore(sqlServer);
db = sqlServer.Databases[databaseName];
db.SetOnline();
sqlServer.Refresh();
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Multiple;
}
public void Disconnect()
{
if (IsConnected)
_connection.Disconnect();
IsConnected = false;
}
}
I ran into a similar problem and I found this solution to be quite helpful.
Take a look - http://www.eggheadcafe.com/software/aspnet/32188436/smorestore-database-name-change.aspx