Mongodb C# filter using LINQ - c#

I have to filter my mongodb collection on the basis of 3 values.
My class structure is
public class Rootobject
{
public object _id { get; set; } //MongoDb uses this field as identity.
public Root root { get; set; }
}
public class Root
{
public Row[] row { get; set; }
}
public class Row
{
public string ID { get; set; }
public string MarketProfileID { get; set; }
public string CodeDetails { get; set; }
public string OfferTypeID { get; set; }
}
I have to apply the filter in mongo db :
var obj = Query.And(
Query<Rootobject>.EQ((c => c.root.row.MarketProfileID, marketProfileID.ToString())
Query<Rootobject>.EQ(c => c.root.row.CodeDetails, code),
Query<Rootobject>.EQ(c => c.root.row.PrivacyLevelID, customerTypeID.ToString())
);
List<Rootobject> obj = objDatabse.GetCollection<Rootobject>("Offer").Find(obj ).ToList();
But it is not compiling.
Please assist
Offer is a mongodb Collection

I recommend to use LINQ syntax here.
Please try this:
IMongoCollection<Rootobject> rootCollection = rootsDatabase.GetCollection<Rootobject>("Offer");
var roots = rootCollection.Find<Rootobject>(r => r.root.row.Any(
row => row.MarketProfileID == "somevalue" &&
row.CodeDetails == "somevalue")).ToList();
Your row class doesn't have PrivacyLevelID, so it would not compile anyways, but I hope you got the idea.

Related

Dynamic Linq Filtering with Parent Property not working

I have question related to dynamic Linq.
I have a class structure defined as below.
public class UserProfile
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public long Overtime { get; set; }
public UserProfileDetails UserProfileDetails { get; set; }
}
public class UserProfileDetails
{
public UserProfileDetails()
{
LstString = new List<string>();
}
public string Department { get; set; }
public double Salary { get; set; }
public int LeaveBalance { get; set; }
public List<string> LstString { get; set; }
}
Created a object of UserProfile like given below.
var a = new UserProfile();
For a normal Linq I can execute the following. I am trying to find all the strings in UserProfileDetails while is not same a my first name.
var vvv = a.UserProfileDetails.LstString.Where(x => !x.Equals(a.FirstName)).ToList();
I want to convert the above linq to dynamic linq and used the following
var vDyna = a.UserProfileDetails.LstString.AsQueryable().Where("!Equals(FirstName)").ToList();
But the above is giving the error:
System.Linq.Dynamic.Core.Exceptions.ParseException: 'No property or field 'FirstName' exists in type 'String''.
Can anyone help me with this please?
I think it's similar to the LINQ function. In the where string you have to use the UserProfile variable a.
Your Code:
var vDyna = a.UserProfileDetails.LstString.AsQueryable().Where("!Equals(FirstName)").ToList();
My suggestion:
var vDyna = a.UserProfileDetails.LstString.AsQueryable().Where(s => !s.Equals(a.FirstName)).ToList();
I never used Dynamic Linq, but maybe that helps.
Source:
https://learn.microsoft.com/en-us/dotnet/api/system.linq.queryable.where?view=net-5.0
EDIT 1:
var vDyna = a.UserProfileDetails.LstString.AsQueryable().Where("!Equals(#0)", a.FirstName).ToList();

How to run complex query with Any() inside Any(). MongoDB Driver C#

I haven't been able to perform a complex query with an Any() inside an Any(), using MongoDB C# Driver..
I have this C# models (equivalent to the mongo database models):
[BsonCollection("alert_evaluations")]
public class AlertEvaluation : Document
{
public ICollection<EvaluationResult> EvaluationResults { get; set; }
public string EvaluationStatus { get; set; }
public DateTime EvaluatedAt { get; set; }
}
public class EvaluationResult
{
public ICollection<EvaluatedLabel> EvaluatedLabels { get; set; }
public double ResultNumber { get; set; }
}
public class EvaluatedLabel
{
public string LabelId { get; set; }
public string Value { get; set; }
}
And I get a list of the next model (as a parameter to filter):
public class EvaluatedLabelFilterDTO
{
public string LabelId { get; set; }
public string Value { get; set; }
}
What I would need to do is to filter AlertEvaluations by getting the ones that have EvaluationResults with EvaluatedLabels that match the same LabelId and Value of the list of EvaluatedLabelFilterDTO objects.
With LinQ I tried something like this:
FilterDefinitionBuilder<AlertEvaluation>.Where(x => x.EvaluationResults.Any(e => e.EvaluatedLabels.Any(z => evaluatedLabelsToFilter.Any(f => f.LabelId == z.LabelId && f.Value == z.Value))));
But of course, this is not supported by mongo..
I'm not really familiar with mongo queries..
Is there any way to do this as a BsonDocument filter query? (Or any other solution).
(The result has to be a FilterDefinition<>, not the list already).
I could really use some help with this. Thanks!

Convert flat to hierarchy list?

I have two tables "CategoryGroup" and "Category" which returns data in one list. Requirement is to convert flat list to hierarchy list like CategoryGroup contains related categories.
Please suggest how to convert into hieararchy list?
public class ProfileConditionGroup
{
public Guid ConditionGroupGUID { get; set; }
public string ConditionGroupName { get; set; }
public List<ProfileConditionList> profileConditions { get; set; }
}
public class ProfileConditionList
{
public string ConditionName { get; set; }
public Nullable<Guid> ConditionGUID { get; set; }
public string[] ThisConditionSelectedByProfileIDs { get; set; }
public Nullable<Guid> ParentConditionGroupGUID { get; set; }
public bool IsDefaultSelected { get; set; }
}
This is actually a little tricky without having an actual concrete return type, but here's the way I'd tackle it if you're just building a tree of Guid values.
Given this query:
var query =
from pcg in pcgs
from pcl in pcg.profileConditions
select new
{
pcg.ConditionGroupName,
pcg.ConditionGroupGUID,
pcl.ConditionName,
pcl.ConditionGUID,
pcl.ThisConditionSelectedByProfileIDs,
pcl.ParentConditionGroupGUID,
pcl.IsDefaultSelected,
};
...I'd do this:
var lookup = query.ToLookup(x => x.ParentConditionGroupGUID);
Func<Guid?, Tree<Guid?>> build = null;
build = g =>
{
var r = new Tree<Guid?>() { Value = g };
r.AddRange(lookup[g].Select(x => build(x.ConditionGroupGUID)));
return r;
};
Now you just call build(null) and you should get a tree of Guid?. If you can create you're own output class you'd change the function to Func<Guid?, Tree<YourOutputClass>>.
You need this class for the tree:
public class Tree<T> : List<Tree<T>>
{
public T Value { get; set; }
}

Find object with in class using LINQ

I want to return the item that has the profile ID I send. So in order to do this I will need to loop through all of the Items -> WebProproperties -> profile. The Class structure is at the end of the question.
I would rather use LINQ than create a nested foreach. I have been trying to get this to work for more than an hour now. I am stuck.
My first idea was to simply use where. But that doesn't work because you need to have something on the other side that needs to equal.
this.Accounts.items.Where(a => a.webProperties.Where(b => b.profiles.Where(c => c.id == pSearchString)) ).FirstOrDefault();
My second idea was to try using Exists which I don't have much experience with:
Item test = from item in this.Accounts.items.Exists(a => a.webProperties.Exists(b => b.profiles.Exists(c => c.id == pSearchString))) select item;
This doesn't work either:
Could not find an implementation of query pattern for source type 'Bool'
public RootObject Accounts {get; set;}
public class RootObject
{
public string kind { get; set; }
public string username { get; set; }
public int totalResults { get; set; }
public int startIndex { get; set; }
public int itemsPerPage { get; set; }
public List<Item> items { get; set; }
}
public class Profile
{
public string kind { get; set; }
public string id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class WebProperty
{
public string kind { get; set; }
public string id { get; set; }
public string name { get; set; }
public string internalWebPropertyId { get; set; }
public string level { get; set; }
public string websiteUrl { get; set; }
public List<Profile> profiles { get; set; }
}
public class Item
{
public string id { get; set; }
public string kind { get; set; }
public string name { get; set; }
public List<WebProperty> webProperties { get; set; }
}
You can use Any() to determine existence. Also, note that many of the extension methods have overloads which take a predicate, including FirstOrDefault():
this.Accounts.items.FirstOrDefault(a => a.webProperties
.Any(b => b.profiles
.Any(c => c.id == pSearchString)));
You are looking for the .Any() operation I think. This will return true/false for whether there are any items matching your query.
For example:
if (this.Accounts.Items.Any(i=>i.webProperties.Any(wp=>wp.profiles.Any(p=>p.id == MySearchId)));
EDIT: You have full answer (was posted while I was composing mine) and as pointed out in comments my answer isn't actually returning your found item, just letting you know whether there is one. You can rework the first .Any to be a .FirstOrDefault to get that match.
E.g.
var result = this.Accounts.Items.FirstOrDefault(i=>i.webProperties.Any(wp=>wp.profiles.Any(p=>p.id == MySearchId)))
You can use the below mentioned code.
var abc = rr.items.Where(p => p.webProperties.Any(c => c.profiles.Any(d => d.id == "1"))).FirstOrDefault();
Just for your reference, your class should look like:
public class RootObject
{
public string kind { get; set; }
public string username { get; set; }
public int totalResults { get; set; }
public int startIndex { get; set; }
public int itemsPerPage { get; set; }
private List<Item> _items=new List<Item>();
public List<Item> items
{
get { return _items; }
set { _items = value; }
}
}

Filtering LINQ child collection EF

Im having some problems trying to do this filtering and im sure it can be done better than what im doing. I will show my classes and how im solving it but i was wondering if I could use Linq to filter this. My Classes:
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public virtual List<FeatureType> Features { get; set; }
}
public class ItemType
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<FeatureType> FeatureTypes { get; set; }
public override string ToString()
{
return Name;
}
}
public class FeatureType
{
public int Id { get; set; }
public string Name { get; set; }
public Section Section { get; set; }
public virtual List<ItemType> ItemTypes { set; get; }
}
I'm trying to get all Sections, and filter Features by an ItemTypeID, so only the FeatureTypes of that ItemTypes are listed. What Im doing now its just getting all sections, and just do a for and just add the ones that work for me in other:
public ItemTypeFeatureViewModel(int myItemTypeId, IUnitOfWork myUnitOfWork)
{
ItemTypeId = myItemTypeId;
unitOfWork = myUnitOfWork;
Sections = unitOfWork.SectionRepository.Get(includeProperties: "Features")
.ToList();
foreach (var item in Sections)
{
var x = new List<FeatureType>();
foreach (var feature in item.Features)
{
foreach (var itemType in feature.ItemTypes)
{
if (itemType.Id == ItemTypeId)
{
x.Add(feature);
break;
}
}
}
item.Features = x;
}
}
Can i improve this and avoid all this foreach?
You can't filter out included collection on server side, but you can replace two inner loops with:
item.Features = item.Features
.Where(f => f.ItemTypes.Any(i => i.Id == ItemTypeId))
.ToList();
That will select only those features which have at least one item type with id you provided.
Try the following:
Sections
.ForEach(x => x.Features = x.Features.Where(y => y.Any(z => z.Id == ItemTypeId))
.ToList());

Categories

Resources