I would like to allowDiskUse:true. However I could not found any example which explain allowDiskUse enabling for MongoDB C# driver.
How can I enable allowDiskUse in MongoDB C# driver?
My sample code like that
var pipeline = new[] { match, project, group, limit, sort, allow };
List<SMBMostInfluentialUser> result = db
.GetCollection<SMBTwitterStatus>("TwitterStatus")
.Aggregate(pipeline).ResultDocuments.Select(x =>
new User
{
Influence = Convert.ToDouble(x["Influence"]),
User = new SMBUser((BsonDocument)x["User"])
}).ToList();
Use the other overload of Aggregate that takes an AggregateArgs parameter and gives you more control over the operation, including setting AllowDiskUse:
var pipeline = new BsonDocument[0]; // replace with a real pipeline
var aggregateArgs = new AggregateArgs { AllowDiskUse = true, Pipeline = pipeline };
var aggregateResult = collection.Aggregate(aggregateArgs);
var users = aggregateResult.Select(x =>
new User
{
Influence = x["Influence"].ToDouble(),
User = new SMBUser(x["user"].AsBsonDocument)
}).ToList();
Note that the return type of this overload of Aggregate is IEnumerable<BsonDocument> so you no longer have to use the ResultDocuments property.
Just to be clear, the Select is being executed client side. You might be able to arrange it so that the documents coming out of your aggregation pipeline can be directly deserialized into instances of one of your classes.
For more recent versions of MongoDB C# driver (not sure starting with what version), the syntax is:
var aggregateOptions = new AggregateOptions{ AllowDiskUse = true};
var aggregateResult = collection.Aggregate(aggregateOptions);
Related
I am using SqlKata purely to build sql queries in C#. I am wanting to take the output of my built up Query, get the raw (compiled) sql string, and execute it against SQL.
I thought this would do it:
var factory = new QueryFactory(null, new SqlServerCompiler());
var query = new Query();
...
var sqlText = factory.Compiler.Compile(query).Sql;
But this gives this:
SELECT TOP (#p0) [AllStarFull].[GameNumber], [AllStarFull].[LeagueId], [AllStarFull].[PlayedInGame] FROM [AllStarFull]
This throws an exception because (#p0) is a param, and not the actual value.
In the documentation, it mentions to bring in Logger but I don't really need logging functionality (right now).
https://sqlkata.com/docs/execution/logging
var db = new QueryFactory(connection, new SqlServerCompiler());
// Log the compiled query to the console
db.Logger = compiled => {
Console.WriteLine(compiled.ToString());
};
var users = db.Query("Users").Get();
Is there anyway to get the raw sql string from the Query with all params populated?
If you need just to build the SQL there is no need to include the SqlKata.Execution package (which is include the QueryFactory class).
The simplest way is:
using SqlKata;
using SqlKata.Compilers;
// Create an instance of SQLServer
var compiler = new SqlServerCompiler();
var query = new Query("Users").Where("Id", 1).Where("Status", "Active");
SqlResult result = compiler.Compile(query);
string sql = result.Sql;
List<object> bindings = result.Bindings; // [ 1, "Active" ]
as mentioned in the docs you can use the result.ToString() to get the full query
var sql = result.ToString();
but this is not a good practice, the correct way is to use the parameterized query with bindings to execute it.
taken from https://sqlkata.com/docs#compile-only-example
If you are injecting QueryFactory dependency, you can use its compiler:
var query = new Query("Users")... etc
var rawSQL = queryFactory.Compiler.Compile(query).RawSql;
I am currently having a text index in my data. I am performing a regex search and I want to make sure that the correct index is used. In the mongo shell I just used explain but how could I use explain in the C# driver?
Here's how I perform my query:
public async Task<IEnumerable<GridFSFileInfo>> Find(string fileName)
{
var filter = Builders<GridFSFileInfo>.Filter.Regex(x => x.Filename, $"/.*{fileName}.*/i");
var options = new FindOptions
{
Modifiers = new BsonDocument("$hint", "filename_text")
};
var result = new List<GridFSFileInfo>();
using (var cursor = await Collection.Find(filter, options).ToCursorAsync())
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
result.AddRange(batch);
}
}
return result;
}
Is there something like Collection.Find(filter, options).Explain() that returns a string or something? I searched on the web and found this: Is there an "Explain Query" for MongoDB Linq? However is seems there is no Explain method...
The modern mongo c# drivers support only one way to configure $explain. You can do it via FindOptions.Modifiers in the same was as you configured $hint above.
var options = new FindOptions
{
Modifiers = new BsonDocument
{
{ "$hint", "filename_text" },
{ "$explain", 1 }
}
};
var cursor = coll.Find(filter, options).As<BsonDocument>().ToCursor();
Pay attention, since $explain completely changes the server response, you should change your output type to BsonDocument(or a type with fields that matches to what explain returns) via As (if it's already not BsonDocument)
The code I'm working on at the moment uses the C# Mongo driver and I do lots of simple stuff like this
var query = Query.EQ("SomeBooleanField", false);
return Collection.FindAs<MyType>(query);
I have a requirement to write a query that is dynamic, i.e. the number of AND clauses varies. So I'm using something like this -
var andList = new List<IMongoQuery>();
if (whatever)
andList.Add(Query.EQ("Field1", true));
if (suchandsuch)
andList.Add(Query.EQ("Field2", false));
var query = new QueryBuilder<MyType>();
query.And(andList);
So my question is, what do I do with query in order to get some results out of it? I want a List or IEnumerable.
I can't find any useful examples online and the driver documentation isn't too helpful. Any help gratefully appreciated.
Have you tried following this format
var collection = _database.GetCollection<BsonDocument>("MyCollection");
var builder = Builders<BsonDocument>.Filter;
var filter = builder.Eq("param1", "value1") & builder.Eq("param2", "value2");
var result = await collection.Find(filter).ToListAsync();
you are getting an error because you cannot use the FindAS<>()is this case
I'm new to mongo in c#
I found tow ways to find documents based on search critiria:
the first using filter:
var collection = _database.GetCollection<BsonDocument>("restaurants");
var filter = Builders<BsonDocument>.Filter.Eq("address.zipcode", "10075");
var result = await collection.Find(filter).ToListAsync();
The second using query:
MongoCollection<BsonDocument> books;
var query = Query.EQ("author", "Kurt Vonnegut");
foreach (BsonDocument book in books.Find(query)) {
// do something with book
}
What's the best way to find documents based to what MongoDB recommendation?
As far I know query builders (like your second example using Query.EQ) belong to old versions of C# drivers (1.X) (see Query class). Also I suggest you to see Builder section in this link that confirm query builders is the old way to consult data.
After the release of the 2.0 version of the .NET driver, a lot of changes were made, including the way of consult the data (you can read more about that in this link). If you are using the last C# driver version you should use your first approach.
The first way you mentioned is quite fine. You might want to incorporate using a mongo cursor as well to allow you to iterate through results
var collection = _database.GetCollection<BsonDocument>("restaurants");
var filter = Builders<BsonDocument>.Filter.Eq("address.zipcode", "10075");
using(var _cursor = await collection.Find(filter).ToCursorAsync())
{
while(await _cursor.MoveNextAsync())
{
foreach(var _document in _cursor.Current) //gets current document
{
//you can do things like get the _id of the document
var _id = _document["_id"];
}
}
}
In the official documentation of mongodb they mention upserts, so it would be really nice to write an upsert command instead of:
if (_campaignRepo.Exists(camp))
{
_campaignRepo.DeleteByIdAndSystemId(camp);
}
_campaignRepo.Save(camp);
something which would implement that logic on the db level if it is possible. So what is the way to do an upsert if there is one?
Version 2 of the MongoDB C# driver requires setting the IsUpsert flag in the write commands. This example will upsert an entire document.
var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
var result = await collection.ReplaceOneAsync(
filter: new BsonDocument("_id", 123),
options: new ReplaceOptions { IsUpsert = true },
replacement: newDoc);
Version 1 of the MongoDB C# driver implements this logic within the Save command.
var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
collection.Save(newDoc);
The Save method is a combination of Insert and Update. If the Id member of the document has a value, then it is assumed to be an existing document and Save calls Update on the document (setting the Upsert flag just in case it actually is a new document after all). Otherwise it is assumed to be a new document and Save calls Insert after first assigning a newly generated unique value to the Id member.
Reference: http://mongodb.github.io/mongo-csharp-driver/1.11/driver/#save-tdocument-method
Note: This does require the proper mapping of the Id field however. More info on that here: http://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#identifying-the-id-field-or-property
Starting from v2.0 of the driver there's a new async-only API. The old API should no longer be used as it's a blocking facade over the new API and is deprecated.
The currently recommended way to upsert a document is by calling and awaiting ReplaceOneAsync with the IsUpsert flag turned on and a filter that matches the relevant document:
Hamster hamster = ...
var replaceOneResult = await collection.ReplaceOneAsync(
doc => doc.Id == hamster.Id,
hamster,
new UpdateOptions {IsUpsert = true});
You can check whether the operation was an insert or an update by looking at ReplaceOneResult.MatchedCount:
The following code is from a working app:
weekplanStore.Update(
Query.EQ("weekNumber", week),
Update.Replace(rawWeekPlan),
UpdateFlags.Upsert);
The weekplanStore is my MongoDB collection, and the code will update the document found with the query in the first argument or insert a new one if none is found. The "trick" is to use the UpdateFlags.Upsert modifier.
The rawWeekPlan is the object inserted or updated, and has the following type:
private class RawWeekPlan
{
public ObjectId id;
public int weekNumber;
public WeekPlanEntry[] entries;
}
and turned into bson by the driver automatically.
You can use the regular update command, but just pass it the Upsert update flag
MongoCollection collection = db.GetCollection("matches");
var query = new QueryDocument("recordId", recordId);
var update = Update.Set("FirstName", "John").Set("LastName","Doe");
matchCollection.Update(query, update, UpdateFlags.Upsert, SafeMode.False);
That code is adapted from a working application (shortened for clarity)