I am using the mongocsharpdriver nuget package (version 1.11.0) to run queries against a mongo database.
When creating a query object in c# I can do this:
var query = Query.EQ("RootValue", "foo");
I can use the nicer generic query Builders instead to do this:
var query = Query<RootObject>.EQ(x=>x.RootValue, "foo");
Now consider this query::
var query = Query.EQ("Things.Value", "bar");
Here Things is a collection of objects that have a string (Value) on them. In this case the query will return any object which has a match in any of the Values of Things.
How do I write this query using the generic Query builder?
I can't work out what expression I need that will get correctly translated to what I want...
In case it makes it clearer here are the classes for my example:
public class RootObject
{
[BsonId]
public ObjectId Id {get; set;}
public IEnumerable<RepeatedObject> Things {get; set;}
public string RootValue {get; set;}
}
public class RepeatedObject
{
public string Value {get; set;}
}
Using this version of the driver, the following query
var query = Query<RootObject>.ElemMatch(x => x.Things, x => x.EQ(y => y.Value, "bar"));
will be translated into the desired MongoDB query:
{ Things: { $elemMatch: { Value: "bar" } } }
Related
I'm using EF core TPH inheritance to model some data and I'm trying to write a query that will query across different subtypes. My current attempt at writing a query cannot be translated to SQL at run time of the query.
public class NameChange : Change {
public string NewName {get; set;}
}
public class AddressChange : Change {
public string NewAddress {get; set;}
}
public class Change {
public long Id {get; set;}
}
Query:
var changes = _context.Changes.Where(x =>
(x as NameChange).NewName == "john" ||
(x as AddressChange).NewAddress== "123 street").ToList();
This query gives me an InvalidOperationException, is there a way to rewrite it so that I am able to write a single query that will query across different subtype properties? If not then I question if I should be using TPH at all. I am using EF Core version 3.1.
Thanks
The way I was casting was not supported with my version of EFCore (facepalm). This code snippet works
var changes = _context.Changes.Where(x =>
((NameChange)x).NewName == "john" ||
((AddressChange)x).NewAddress== "123 street").ToList();
I want to push an element to an array inside another array inside a document using LINQ with latest MongoDb driver
here is the code:
public class Contract : BaseDocument
{
public ObjectId Id {get;set;}
...
public List<Payment> Payments {get;set;}
}
public class Payment : BaseDocument
{
public ObjectId Id {get;set;}
public double TotalPaymentAmount {get;set;}
public DateTime PaymentWorthDate {get;set;}
...
public List<PaymentTransaction> PaymentTransactions {get;set;}
}
public class PaymentTransaction
{
public double AmountPaid {get;set;}
public DateTime TransactionDateTime {get;set;}
}
So how to push new PaymentTransaction to a specific Payment in a particular Contract using 'LINQ Expression' ?
Thanks!
LINQ stands for Language-Intergrated Query while you're trying to update the document so actually you need UpdateOne method. Since you have more than one nested array you can leverage regular query to identify Contract along with the $ positional operator to indicate which Payment (nested object) should be modified.
.NET MongoDB driver offers a special syntax where you can pass -1 as an index to indicate that this item will be identified based on filtering condition. Try:
var filterBuilder = Builders<Contract>.Filter;
var filter = filterBuilder.Eq(x => x.Id, contractId) &
filterBuilder.ElemMatch(doc => doc.Payments, el => el.Id == paymentId);
var updateBuilder = Builders<Contract>.Update;
var update = updateBuilder.Push(doc => doc.Payments[-1].PaymentTransactions, new PaymentTransaction());
col.UpdateOne(filter, update);
I am using EF6 and I noticed that when I "include" a child table in a query, EF triggers a new query for each one of the parent rows...is that ok? is there a way to avoid it and make it bring all the information with the main query only?
Here are my entities (not the exact code):
public class Contractor
{
public int id { get; set;}
public IEnumerable<ContractorEmployee> Employees;
}
public class ContractorEmployee
{
public int id { get; set;}
public int contractorId { get; set;}
}
And this is the query:
var fullContractors = dbContext.Contractors.Include("ContractorEmployee");
so if the fullContractors query retrieves 5 contractors, I see 5 extra queries in SQL bringing the contractor employees of each one of them.
Any way to avoid this and bring it all in the first "SELECT"???
Include method takes the name of the parameter as string it is recommended to use overloaded version of Include that takes Expression as parameter.
You can have look at the overloaded version of extension method here.
So do it Either
var fullContractors = dbContext.Contractors.Include("Employees");
or go with Expression version like this:
var fullContractors = dbContext.Contractors.Include(d => d.Employees);
Here's the setup, I've got an object that contains a list of events like so:
public class Order
{
public string Name {get; set;}
public List<OrderEvent> OrderEvents {get; set;}
public bool IsComplete() => OrderEvents.Any(e => e.GetType() == typeof(OrderComplete));
}
public class OrderEvent
{
public DateTime TimeStamp {get; set;}
}
public class OrderSubmitted : OrderEvent {...quantity ect...}
public class OrderPaidFor : OrderEvent {...amounts...}
public class OrderComplete : OrderEvent {...more stuff...}
Now I can dump this data into the database and pull it out and all is good, but how do I write a query to just get the completed orders without pulling all the orders client side and filtering there?
I've tried the following query but I've been told that I can't translate GetType like that.
Session.Query<Order>()
.Where(o => o.Events.Any(e => e.GetType() == typeof(OrderComplete)))
.ToList();
I'm pretty sure there's a good way to do this using JObjects and querying the $type property, but google and my efforts haven't come up with anything good yet.
Thanks.
What you can do is make the IsComplete() function a read only property instead. That way it would serialize down to IsComplete: true/false in the stored document.
Then you should be able to query like this:
Session.Query<Order>()
.Where(o => o.IsComplete)
.ToList();
Hope this helps!
I am having trouble with expressing this query in C# MongoDB, I want it to return all the results of an objectID where it does not equal to "000000000000000000000000" which works in MongoVue; But I can't get it work in my program.
{"ProfilePictureId" : {$ne: new ObjectId ("000000000000000000000000")}}
I am using official C# driver:
var query = new QueryDocument();
foreach (BsonDocument book in col.Find(query))
{
...
}
You can build your query as follows:
var query = Query.NE("ProfilePictureId", ObjectId.Empty);
ObjectId.Empty returns an ObjectId composed of all zeroes.
Assuming that you are querying for documents of a class looking something like:
public class Profile {
public ObjectId ProfilePictureId { get; set; }
//... other attributes, construcotrs, methods etc...
}
You can also write your query using expression lambdas like this:
var query = Query<Profile>.NE(s => s.ProfilePictureId, ObjectId.Empty);