I am facing problem while Querying the following in MongoDB C#. My code in mongo client is
db.collection.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ,{price:100},{name:"x"}] } )
but how to query the same in C#.
I was able to query the following mongo client code statement
db.collection.find({type:"food"},{name:1,quantity:1})
as
var match = new BsonDocument() { { "$match", new BsonDocument { {"type":"food" } } } };
var project = new BsonDocument(){ { "$project", new BsonDocument{ { "name", 1 } { "quantity", 1 } } } };
AggregateArgs AggregationPipeline = new AggregateArgs() { Pipeline = new[] { match, project } };
var aggregate = Collection.Aggregate(AggregationPipeline);
I am using Mongo C Sharp Driver 1.9.2.
Thanks.
First, add a builder:
var builder = Builders<BsonDocument>.Filter;
Then a filter like this:
var filter = builder.Lt("quantity", 20) | builder.Eq("price", 10) | other stuff)
And finally something like:
db.collection.Find(filter).ToList();
Related
I have .NET Application that uses MongoDB. Current driver I am using is 1.9.2. I am trying to upgrade it to 2.7.0.
I am having some difficulty in getting an Aggregate query to work in the new version:
The working code in version 1.9.2 of the driver is:
public IEnumerable<Car> GetCarsModifiedInPeriod(DateTimeOffset dateFrom, DateTimeOffset dateTo)
{
var matchRequestFromDate = new BsonDocument
{
{
"$match",
new BsonDocument
{
{
// Filter out those too recently modified
"LastUpdatedOn.0", new BsonDocument {{"$gte", dateFrom.Ticks}}
}
}
}
};
var matchRequestToDate = new BsonDocument
{
{
"$match",
new BsonDocument
{
{
// Filter out those too recently modified
"LastUpdatedOn.0", new BsonDocument {{"$lte", dateTo.Ticks}}
}
}
}
};
var cars = collection.Aggregate(new AggregateArgs
{
Pipeline = new[] { matchRequestFromDate, matchRequestToDate},
AllowDiskUse = true,
// Setting the OutputMode to Cursor allows us to return Mongo Doc Size > 16 MB - in the case when a large date
// range is used or a large number of cars were modified in a short period of time
OutputMode = AggregateOutputMode.Cursor
}).Select(r => r.Values.Select(c => c.AsObjectId.ToString()).First());
var returnData = collection.AsQueryable().Where(c => cars.Contains(c.Id)).Select(c => c);
return returnData;
}
With a breakpoint set on returnData for the two periods specified I am getting a count of 25 cars which is what I expect.
This is how I have attempted to re-write for 2.7.0 version of driver:
public IEnumerable<Car> GetCarsModifiedInPeriod(DateTimeOffset dateFrom, DateTimeOffset dateTo)
{
var matchRequestFromDate = new BsonDocument
{
{
"$match",
new BsonDocument
{
{
// Filter out those too recently modified
"LastUpdatedOn.0", new BsonDocument {{"$gte", dateFrom.Ticks}}
}
}
}
};
var matchRequestToDate = new BsonDocument
{
{
"$match",
new BsonDocument
{
{
// Filter out those too recently modified
"LastUpdatedOn.0", new BsonDocument {{"$lte", dateTo.Ticks}}
}
}
}
};
var pipeline = new[] {matchRequestFromDate, matchRequestToDate};
//var mongoPipeline = new AggregateArgs { Pipeline = pipeline, AllowDiskUse = true, OutputMode = AggregateOutputMode.Cursor };
var aggregate = collection.Aggregate(); //.Match(mongoPipeline);
aggregate.Options.AllowDiskUse = true;
aggregate.Options.UseCursor = true;
foreach (var pipe in pipeline)
{
aggregate.AppendStage<BsonDocument>(pipe);
}
var returnData = aggregate.ToList();
return returnData;
}
If I set a breakpoint in returnData in this method I am getting a count of around 10K cars so it doesnt look like I am correctly applying the same matches
Is there a reason you are doing everything in BsonDocuments? There are methods that would make your life a lot easier, for example something like this.
collection.Aggregate(new AggregateOptions() { AllowDiskUse = true, UseCursor = true })
.Match(Builders<BsonDocument>.Filter.Gte("LastUpdatedOn.0", dateFrom.Ticks) & Builders<BsonDocument>.Filter.Lte("LastUpdatedOn.0", dateFrom.Ticks))
.ToListAsync()
You could tidy the filtering up more as well by using the right class for the collection and the builders.
Looking at the query, I'm not sure you even need to be using an aggregate unless you are doing more than a match. It could simply be a find.
I can run it in Robomongo, but I do not know how to do this in C #
db.mycollection.aggregate([
{$match : { "Partner._id": {$in: ["acb123","def456"]}}},
{$group : {_id: {status: "$Status"}, count: {$sum: 1}}}
])
You can use fluent aggregation and simply parse BsonDocuments from JSON strings:
var result = await mycollection.Aggregate()
.Match(BsonDocument.Parse("{ 'Partner._id': {$in: ['acb123','def456']} }"))
.Group(BsonDocument.Parse("{ _id: '$Status', count: {$sum: 1} }"))
.ToListAsync();
Or you can build BsonDocuments manually:
var result = await mycollection.Aggregate()
.Match(
new BsonDocument {
{"Partner._id", new BsonDocument("$in", new BsonArray(new []{"acb123","def456"}))}
}
).Group(
new BsonDocument {
{ "_id", "$Status" }, // thus you group by single field
{ "count", new BsonDocument("$sum", 1) }
}
).ToListAsync();
I am trying to display/list data after using aggregation function but it isn't happening.
This code works absolutely fine.
var connectionstring = "mongodb://localhost:27017";
var client = new MongoClient(connectionstring);
var db = client.GetDatabase("school");
var col = db.GetCollection<BsonDocument>("students");
var filter = new BsonDocument("type", "homework");
var filter2 = Builders<BsonDocument>.Filter.Eq("scores.type", "homework");
var myresults = await col.Find(filter2)
.Limit(2)
.Project("{name:1,scores:1,_id:0}")
.Sort("{score:1}")
.ToListAsync();
foreach (var result in myresults)
{
Console.WriteLine(result);
}
This code fetches document as it should however when I replace
var myresults = await col.Find(filter2)
.Limit(2)
.Project("{name:1,scores:1,_id:0}")
.Sort("{score:1}")
.ToListAsync();
with this
var myresults = await col.Aggregate()
.Unwind("{$scores}")
.Group(new BsonDocument { { "_id", "$_id" }, { "lowscore", new BsonDocument("$min", "$scores.score") } })
//.Group("{_id:'$_id',lowscore:{$min:'$scores.score'}}")
.ToListAsync();
No record is being pulled.
I do not want to use Pipeline method. I simply want to display the result obtained via aggregate function.
This is my Mongo Query (I want the same result as this in C#)-
db.students.aggregate([{$sort:{_id:-1}},{$unwind:"$scores"},{$group:{_id:"$_id", lowscore:{"$min":"$scores.score"}}}])
Building aggregation pipeline is bit tricky.
Try:
var pipeline = new BsonDocument[] {
new BsonDocument{ { "$sort", new BsonDocument("_id", 1) }},
new BsonDocument{{"$unwind", "$scores"}},
new BsonDocument{{"$group", new BsonDocument{
{"_id", "$_id"},
{"lowscore",new BsonDocument{
{"$min","$scores.score"}}
}}
}}
};
var result = collection.Aggregate<BsonDocument> (pipeline).ToListAsync();
If you do pipeline.ToJson(), you'll get following JSON equivalent string which is same as of your original and tested MongoShell query.
[
{
"$sort": {
"_id": 1
}
},
{
"$unwind": "$scores"
},
{
"$group": {
"_id": "$_id",
"lowscore": {
"$min": "$scores.score"
}
}
}
]
This is wrong... {$scores} isn't even valid json. Remove the curly braces and the dollar sign from the $unwind directive.
The parameter name is field, so you need to provide a field name to it.
Try with writing only $score instead of #scores.score. may be it helpful.
db.students.aggregate([{$sort:{_id:-1}},{$unwind:"$scores"},{$group:{_id:"$_id", lowscore:{"$min":"$score"}}}])
I started out with Mongo client doing some nifty queries and aggretations.. but now that I want to use it in .NET/C#, I see that I can't simply run the query as text field..
Furthermore, after resorting to building an Aggregation Pipeline, and running the collection.Aggregate() function, I'm getting a result set, but I have no idea how to traverse it..
Can anyone help guide me here?
Here's my code:
var coll = db.GetCollection("animals");
var match = new BsonDocument {
{ "$match", new BsonDocument {{"category","cats"}} }
};
var group = new BsonDocument{
{
"$group", new BsonDocument{
{"_id", "$species"},
{"AvgWeight", new BsonDocument{{"$avg", "$weight"}}} }
}
};
var sort = new BsonDocument{{"$sort", new BsonDocument{{"AvgWeight", -1}}}};
var pipeline = new[] { match, group, sort };
var args = new AggregateArgs { Pipeline = pipeline };
var res = coll.Aggregate(args);
foreach (var obj in res)
{
// WHAT TO DO HERE??
}
Also, I should say that I'm a little rusty with C# / ASP.NET / MVC so any room for simplification would be much appreciated.
Your result is IEnumerable of BsonDocument, you can Serialize them to C# objects using the BSonSerializer. And this code snippet just writes them to your console, but you can see that you have typed objects
List<Average> returnValue = new List<Average>();
returnValue.AddRange(documents.Select(x=> BsonSerializer.Deserialize<Average>(x)));
foreach (var obj in returnValue)
{
Console.WriteLine("Species {0}, avg weight: {1}",returnValue._Id,returnValue.AvgWeight);
}
And then have a class called Average, where the property name match the names in the BSonDocument, if you want to rename then (because _Id is not so nice in c# terms concerning naming conventions), you can add a $project BsonDocument to your pipeline.
public class Average
{
public string _Id { get; set; }
public Double AvgWeight {get; set; }
}
$project sample (add this in your pipeline just before sort
var project = new BsonDocument
{
{
"$project",
new BsonDocument
{
{"_id", 0},
{"Species","$_id"},
{"AvgWeight", "$AvgWeight"},
}
}
};
i have one collection in which i am doing insert/update operation. for insert i use the code:
MongoCollection<BsonDocument> tblCity = mydb.GetCollection<BsonDocument>("tblCity");
BsonDocument CollectionCity = new BsonDocument {
{ "CityCode", cityCode },
{ "CityName", cityName },
{ "stamps" , new BsonDocument {
{"ins", DateTime.Now},
{"upd", ""},
{"createUsr", UserId},
{"updUsr", ""},
{"Ins_Ip", ""},
{"Upd_IP", GetIP()}
}
}
};
tblCity.Insert(CollectionCity);
it is working fine. but while i am updating i am using code:
MongoCollection <BsonDocument> tblCity = mydb.GetCollection<BsonDocument>("tblCity");
var query = new QueryDocument { { "City_strCode", cityCode } };
var update = new UpdateDocument {
{ "$set", new BsonDocument("City_strName", cityName) },
{ "stamps" , new BsonDocument{
{"upd", DateTime.Now},
{"updUsr", ""},
{"Upd_IP", GetIP()
}}
}};
tblCity.Update(query, update);
But problem is that with out changing the ins date i want to update upd field. But it is removing the ins field and updating the upd field. I am trying a lot of ways but not able to get any solution. Please suggest something....Even I got some links based on this and tried.. but none of them workout.
You'll need to fix your use of $set and the query.
Your query doesn't match with the field name in the inserted document.
var query = new QueryDocument { { "CityCode", cityCode } };
If you're using $set, then pass all of the fields you want to change as part of the BsonDocument:
var query = new QueryDocument { { "CityCode", cityCode } };
var update = new UpdateDocument {
{ "$set", new BsonDocument {
{ "CityName", "San Fran"},
{ "stamps.upd" , DateTime.Now()},
{ "stamps.updUsr", ""},
{ "stamps.Upd_IP", "10.0.0.1" }
}}};