MoonKnight
MoonKnight

Reputation: 23833

MongoDb.Driver IMongoDatabase.GetCollectionNamesAsync() Exception

I connect to a MongoDB using the C# MongoDB.Driver library. Some code that works

MongoClient client = MongoClientBuilder.Build(
    "77.199.99.90", 27016, "admin", "pwd");
IReadOnlyList<string> dbNames = this.client.GetDatabaseNamesAsync().Result;
foreach (var dbn in dbNames)
{
    IMongoDatabase mongoDb = client.GetDatabase(dbn);
    var cNames = mongoDb.GetCollectionNamesAsync().Result; <- THIS THROWS AggregateException.
    foreach (var cn in cNames)
    {
        ...
    }
}

So the credentials are correct and I get my IMongoDatabases just fine, however, when I attempt to retrieve the collections within a database, I get an AggregateException when I do mongoDb.GetCollectionNamesAsync().Result, the exception details are

AggregateException InnerException (count 1) MongoQueryException: QueryFailure flag was true (response was { "$err" : "not authorized for query on taurusEvents.system.namespaces", "code" : 13 }).

I am not sure what this exception is telling me. The authentication on the client is fine, but I can seem to query the database. What am I missing here?


Edit. I now realise that I needed to use a credential to do this, however, doing

public static MongoClient Build(string host, int port,
    string username, string password, string authDb)
{
    MongoCredential cred = MongoCredential.CreateMongoCRCredential(authDb, username, password);
    MongoClientSettings settings = new MongoClientSettings()
    {
        Credentials = new[] { cred }, 
        Server = new MongoServerAddress(host, port)
    };
    return new MongoClient(settings);
}

where I am now providing my authentication database name authDb also throws the same inner exception above.


Edit#2. I have found that if I do

var o = database.GetCollection<BsonDocument>("events");

with an explicit reference to the collection name, it works, I get my collection. But I want a list of the collections avalible, why is GetCollectionNamesAsync() not working?


Edit#3. I create my server roles using:

1. Create an admin user:

use admin
db.createUser({user: "admin", pwd: "*******", roles: [{role: "userAdminAnyDatabase", db: "admin"}]})

2. Create other users eg:

use admin
db.createUser({user: "mel", pwd: "*******", roles: [{role: "readWrite", db: "taurusEvents"}, {role: "readWrite", db: "taurusOdds"}, {role: "readWrite", db: "taurusState"}]})

Thanks for your time.

Upvotes: 3

Views: 3294

Answers (2)

Robert Stam
Robert Stam

Reputation: 12187

GetCollection and GetCollectionNamesAsync are different.

GetCollection merely creates a client side object that represents a collection. It doesn't actually talk to the server (so authentication would never be an issue).

GetCollectionNamesAsync talks to the server to fetch the names of all the collections for a given database. This requires that the username you authenticated with have at least read permission on that database.

Upvotes: 1

Robert Stam
Robert Stam

Reputation: 12187

You are getting an AggregateException because of the way .Result works in .NET.

var result = task.Result; // throws an AggregateException if the task faulted

To have your code throw the inner exception use either:

var result = task.GetAwaiter().GetResult(); // throws the inner exception if the task faulted
var result = await task; // also throws the inner exception if the task faulted

I suspect that the reason you are getting this exception is that while you are using valid credentials (if not you would have failed sooner), the user you are authenticating as does not have permission to read the taurusEvents database.

Upvotes: 1

Related Questions