How to get Nested results of LINQ Groupby - c#

My code is as below
GetDairyHeaderInfoByEmail(id)
.Where(p => p.ATTRIBUTE15 == id)
.Select(jk=> new {
jk.HEADER_ID_PK,
jk.VENDOR_ID,
jk.VENDOR_SITE_ID,
jk.VENDOR_NAME,
jk.ADDRESS_LINE1,
jk.ATTRIBUTE15
})
.GroupBy(p => p.HEADER_ID_PK)
.Select(p => new {
header_id_pk = p.Key,
invoice_id_pk = _ippDetailServices.GetDairyHeaderInfoByEmail(id).Where(k => k.HEADER_ID_PK == p.Key).Select(c => new { c.APP_INVOICES_ID_PK, c.INVOICE_TYPES, c.IS_HOURLY }).ToList() }).ToList();
The results I see is as below
[ {
"header_id_pk": 800.0,
"invoice_id_pk": [
{
"APP_INVOICES_ID_PK": 1058.0,
"INVOICE_TYPES": "EPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1059.0,
"INVOICE_TYPES": "CPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1060.0,
"INVOICE_TYPES": "WHT ON DIVIDEND",
"IS_HOURLY": "N"
},
{
"APP_INVOICES_ID_PK": 1061.0,
"INVOICE_TYPES": "L.P",
"IS_HOURLY": "N"
}
] } ]
But I want the results as below
[ {
"header_id_pk": 800.0,
"HEADER_ID_PK" : 800.0,
"VENDOR_ID" : 12.0,
"VENDOR_SITE_ID" : 33.0,
"VENDOR_NAME" : Faisal,
"ADDRESS_LINE1" : XYZ address,
"invoice_id_pk": [
{
"APP_INVOICES_ID_PK": 1058.0,
"INVOICE_TYPES": "EPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1059.0,
"INVOICE_TYPES": "CPP",
"IS_HOURLY": "Y"
},
{
"APP_INVOICES_ID_PK": 1060.0,
"INVOICE_TYPES": "WHT ON DIVIDEND",
"IS_HOURLY": "N"
},
{
"APP_INVOICES_ID_PK": 1061.0,
"INVOICE_TYPES": "L.P",
"IS_HOURLY": "N"
}
] } ]
Sorry about the mess if any, this is my first question.
Thanks

var dairy = _ippDetailServices.GetDairyHeaderInfoByEmail(id).Where(p =>
p.ATTRIBUTE15 == id).Select(jk=> new { jk.HEADER_ID_PK,
jk.VENDOR_ID,
jk.VENDOR_SITE_ID,
jk.VENDOR_NAME,
jk.ADDRESS_LINE1,
jk.ATTRIBUTE15
}).GroupBy(p => new { p.HEADER_ID_PK,
p.VENDOR_ID, p.VENDOR_SITE_ID,
p.VENDOR_NAME, p.ADDRESS_LINE1,
p.ATTRIBUTE15 }).Select(p => new {
header_id_pk = p.Key, invoice_id_pk =
_ippDetailServices.GetDairyHeaderInfoByEmail(id).Where(k => k.HEADER_ID_PK ==
p.Key.HEADER_ID_PK).Select(c => new { c.APP_INVOICES_ID_PK,
c.INVOICE_TYPES,
c.IS_HOURLY }).ToList() }).ToList();
I figured it out, I just needed to add those master columns in my Group By clause.

Related

Get summation of all field in mongodb c#

I have a mongodb which looks like this
[
{
"client_id": "abc",
"product_id": "123",
"weight": {
"value": 100
"unit": "kg"
}
},
{
"client_id": "def",
"product_id": "456",
"weight": {
"value": 200
"unit": "kg"
}
}
]
I need to get summation of weight value for a certain client id and product id using mongodb c# client, how can I do that?
I tried this but it is always returning 0
var total_weight = await Collection.AsQueryable()
.Where(
x => x.client_id == "abc" &&
x => x.product_id== "123")
.SumAsync(x => x.weight.value);
Thanks
I think you are looking for this query so you can try this code:
var total_weight = await Collection.AsQueryable<YourModel>()
.Where(x => x.client_id == "abc" && x.product_id == "123")
.GroupBy(x => new { x.client_id, x.product_id })
.Select(x => x.Sum(y => y.weight.value))
.FirstOrDefaultAsync();

C# MongoDB Filter returns the whole object

I'm trying to create a MongoDB filter in C#.
For example i have a JSON object like this :
"Username": "Tinwen",
"Foods": [
{
"Fruit": "Apple",
"Amount": 1
},
{
"Fruit": "Banana",
"Amount": 2
},
{
"Fruit": "Mango",
"Amount": 3
},
{
"Fruit": "Strawberry",
"Amount": 3
}
]
}
And i want to create a filter that returns only the objects in the array with Amount == 2 || Amount == 3:
{
"Username": "Tinwen",
"Foods": [
{
"Fruit": "Banana",
"Amount": 2
},
{
"Fruit": "Mango",
"Amount": 3
},
{
"Fruit": "Strawberry",
"Amount": 3
}
]
}
I've already tried filter like this :
var amountFilter= Builders<MyObject>.Filter.ElemMatch(
m => m.Foods,
f => f.Amount == 2 || f.Amount == 3);
And this one :
var expected = new List<int>();
expected.Add(2);
expected.Add(3);
var amountFilter = Builders<MyObject>.Filter.And(Builders<MyObject>.Filter.ElemMatch(
x => x.Foods, Builders<Foods>.Filter.And(
Builders<Foods>.Filter.In(y => y.Amount, expected))));
But every time it returns me the whole object (with the full array).
For now i'm using LinQ like this:
List<MyObject> res = _messageCollection.Find(amountFilter).ToEnumerable().ToList();
foreach (var msg in res)
{
for (int j = 0; j < msg.Foods.Count; j++)
{
if (!expected.Contains(msg.Foods[j].Amount))
{
msg.Foods.RemoveAt(j);
}
}
}
for (int i = 0; i < res.Count; i++)
{
if (res[i].Foods.Count == 0)
{
res.RemoveAt(i);
}
}
But I'm pretty sure it can be down using MongoDB filter (and also because it's pretty bad with LinQ). So if anyone have an answer that can help me !
you can do it with linq like following. but you gotta make the Foods property IEnumerable<Food>
public class User
{
public string Username { get; set; }
public IEnumerable<Food> Foods { get; set; }
}
the following query will do a $filter projection on the Foods array/list.
var result = await collection
.AsQueryable()
.Where(x => x.Foods.Any(f => f.Amount == 2 || f.Amount == 3))
.Select(x => new User
{
Username = x.Username,
Foods = x.Foods.Where(f => f.Amount == 2 || f.Amount == 3)
})
.ToListAsync();

ElasticSearch & Nest - Wrong convertion

I have this pure call to Elastic that works. It returns 29 docs:
GET /idxsearch-test/movies/_search
{
"size": 20,
"query": {
"bool": {
"must": {
"bool" : {
"should": [
{"term": {"tag.name": "Paris"}},
{"multi_match" : {
"operator": "and",
"query" : "Paris",
"fields": ["movie_title.default^10",
"movie_title.snowball^2",
"movie_title.shingles^2",
"movie_title.ngrams"]}}
]
}
},
"filter": {
"term": { "is_adult": false }
}
}
},
"_source": ["id_content", "movie_title", "vote_average", "tag.name", "is_adult"]
}
I need to use Nest, so I converted to this. It returns 0:
var vod = client.Search<dynamic>(s => s
.Size(10)
.From(1)
.Index(defaultIndex)
.Type("movies")
.Query(qry1 => qry1
.FunctionScore(fs =>
fs.Query(qry2 =>
qry2.Bool(bool1 =>
bool1.Must(must1 =>
must1.Bool(bool2 =>
bool2.Should(should1 =>
{
QueryContainer qc = null;
qc &= should1.Term(tt => tt.Field("tag.name").Value(keywords));
qc &= should1.MultiMatch(mm1 => mm1.Fields(ff => ff
.Field("movie_title.default^10")
.Field("movie_title.snowball^2")
.Field("movie_title.shingles^2")
.Field("movie_title.ngrams"))
.Operator(Operator.And)
.Query(keywords));
return qc;
})
)
)
.Filter(fil =>
{
QueryContainer query = null;
if (!includeAdult)
query &= fil.Terms(fil2 => fil2.Field("is_adult").Terms(false));
return query;
})
)
)
.BoostMode(FunctionBoostMode.Sum)
.Functions(ff => ff.FieldValueFactor(fv => fv.Field("vote_average")
.Factor(0.5)
.Modifier(FieldValueFactorModifier.Log1P)))
))
);
But the results are different... What am I missing?
Is there a way to make the same call in a cleaner and correct way?
cheers
The first query can be written as
//Fluent
client.Search<dynamic>(
s => s.
Index("idxsearch-test").
Type("movies").
Take(20).
Query(q => q.Bool(
b => b.Must(m => m.Term(t => t.Field("tag.name").Value("Paris")) ||
m.MultiMatch(mm => mm.Fields(f => f.
Field("movie_title.default", 10).
Field("movie_title.snowball", 2).
Field("movie_title.shingles", 2).
Field("movie_title.ngrams")))).
Filter(f => includeAdult ? f.Term(t => t.Field("is_adult").Value("")) : null))).
Source(sc => sc.Includes(i => i.Field("id_content").Field("movie_title").Field("vote_average").Field("tag.name").Field("is_adult"))));
//Object
client.Search<dynamic>(new SearchRequest<dynamic>("idxsearch-test", "movies")
{
Size = 20,
Query = new BoolQuery
{
Must = new QueryContainer[]
{
new BoolQuery
{
Should = new QueryContainer[]
{
new TermQuery() { Field = "tag.name", Value = "Paris" },
new MultiMatchQuery
{
Fields = new [] { "movie_title.default^10", "movie_title.snowball^2", "movie_title.shingles^2", "movie_title.ngrams" }
}
}
}
},
Filter = includeAdult ? new QueryContainer[]
{
new TermQuery { Field = "is_adult", Value = false }
} : null
},
Source = new Union<bool, ISourceFilter>(new SourceFilter { Includes = new[] { "id_content", "movie_title", "vote_average", "tag.name", "is_adult" } })
});

Elasticsearch - Order search results ASC

having a problem with my elasticsearch.
Setup: Having a Company-Class with the data field "companyName".
My search shall search and response all companys with the searched term.
If I try to sort via
.Sort(x=> x.OnField(x => x.CompanyName).Descending())
The data aren't sorted rightly - reference stackOverflow
I tried the given solution, but if I set my companyName to "not_analyzed" I cant even search anymore for the comnpany name or like a beginning "goo" (google)
So I tried to set up a multifield mapping, with a suffix, which isn't analyzed and one which is analyzed.
My Index is set up like:
client.CreateIndex(IndexName, c => c
.AddMapping<Exhibitor>(m =>m
.MapFromAttributes()
.Properties(o => o
.MultiField(mf=>mf
.Name(x=>x.CompanyName)
.Fields(fs => fs
.String(s=>s.Name(t=>t.CompanyName).Index(FieldIndexOption.Analyzed).Analyzer("standard"))
.String(s=>s.Name(t=>t.CompanyName.Suffix("raw")).Index(FieldIndexOption.NotAnalyzed))))
)
)
)
);
My search looks like:
string SearchTerm ="my search term"
results = GetClient().Search<Company>(s => s
.Query(qa => qa
.MatchPhrasePrefix(m => m
.OnField(f=>f.CompanyName)
.Query(SearchTerm)
))
.Sort(x => x.OnField(x => x.CompanyName.Suffix("raw")).Descending())
.Size(maxResults).Skip(page * pageSize).Take(pageSize)
);
But that still doesn't work.
Any ideas?
Thanks in advance.
Update 1:
For case insensitive sorting I added an custom analyzer:
var companyAnalyzer = new CustomAnalyzer
{
Filter = new List<string> { "standard", "lowercase" },
Tokenizer = "keyword"
};
client.CreateIndex(IndexName, c => c
.Analysis(analysis => analysis
.Analyzers(a => a
.Add("companyanalyzer", companyAnalyzer)
)
)
.AddMapping<Exhibitor>(m => m
.MapFromAttributes()
.Properties(o => o
.MultiField(mf => mf
.Name(x => x.CompanyName)
.Fields(fs => fs
.String(s => s.Name(t => t.CompanyName).Index(FieldIndexOption.Analyzed).Analyzer("standard"))
.String(s => s.Name(t => t.CompanyName.Suffix("raw")).Index(FieldIndexOption.Analyzed).Analyzer("companyanalyzer"))))
)
)
);
This example is working, maybe it will put some light on your issue.
var indicesResponse = client.DeleteIndex(descriptor => descriptor.Index(indexName));
client.CreateIndex(indexName, c => c
.AddMapping<Exhibitor>(m => m
.MapFromAttributes()
.Properties(o => o
.MultiField(mf => mf
.Name(x => x.CompanyName)
.Fields(fs => fs
.String(s => s.Name(t => t.CompanyName).Index(FieldIndexOption.Analyzed).Analyzer("standard"))
.String(s => s.Name(t => t.CompanyName.Suffix("raw")).Index(FieldIndexOption.NotAnalyzed))))
)));
client.Index(new Exhibitor { Id = 1, CompanyName = "a test" });
client.Index(new Exhibitor { Id = 2, CompanyName = "b test" });
client.Index(new Exhibitor { Id = 3, CompanyName = "c test" });
client.Refresh();
string SearchTerm = "test";
var results = client.Search<Exhibitor>(s => s
.Query(qa => qa
.MatchPhrasePrefix(m => m
.OnField(f => f.CompanyName)
.Query(SearchTerm)
))
.Sort(x => x.OnField(f => f.CompanyName.Suffix("raw")).Descending())
);
Result of this query:
{
"took": 2,
"timed_out": false,
"_shards": {..}
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "my_index",
"_type": "exhibitor",
"_id": "3",
"_score": null,
"_source": {
"id": 3,
"companyName": "c test"
},
"sort": [
"c test"
]
},
{
"_index": "my_index",
"_type": "exhibitor",
"_id": "2",
"_score": null,
"_source": {
"id": 2,
"companyName": "b test"
},
"sort": [
"b test"
]
},
{
"_index": "my_index",
"_type": "exhibitor",
"_id": "1",
"_score": null,
"_source": {
"id": 1,
"companyName": "a test"
},
"sort": [
"a test"
]
}
]
}
}
Index mapping:
{
"my_index" : {
"mappings" : {
"exhibitor" : {
"properties" : {
"companyName" : {
"type" : "string",
"analyzer" : "standard",
"fields" : {
"raw" : {
"type" : "string",
"index" : "not_analyzed"
}
}
},
"id" : {
"type" : "integer"
}
}
}
}
}
}
Hope it helps.

Search in list of expandoObject

Suppose I have a List of dynamic objects like:
var records = [
{
"Id": 1,
"Name": "sai",
"Age": "4",
"About": "12.02.1991"
},
{
"Id": 2,
"Name": "hjfh",
"Age": "2",
"About": "12.02.1991"
},
{
"Id": 3,
"Name": "hello name",
"Age": "6",
"About": "hi"
},
{
"Id": 4,
"Name": 1,
"Age": "9",
"About": "hello world"
}
]
string searchString = "Hello";
I tried something like:
foreach (var item in records )
{
foreach (var field in item)
{
if (field.Value != null && field.Value.ToString().IndexOf(query.SearchString, StringComparison.OrdinalIgnoreCase) >= 0)
{
count++;
break;
}
}
}
I want the count of records which has searchString at any field in the record. but can I write this using a LINQ query?
This is your code, converted to a linq expression:
You have access to the field and the object in the select statement.
records.Cast<ExpandoObject>().SelectMany(x => x, (obj, field) => new { obj, field })
.Where(x => x.field.Value != null && x.field.Value.ToString().IndexOf(SearchString, StringComparison.OrdinalIgnoreCase) >= 0)
.Select(x => x.field.Key);
To count the number of objects that have at least one field that contains the searchstring:
records.Cast<ExpandoObject>()
.Where(x => x.Any(y => y.Value != null && y.Value.ToString().IndexOf(SearchString, StringComparison.OrdinalIgnoreCase) >= 0))
.Count();
It would be something like this:
logic:
var qry = records.Where(x=>x.Field.Contains(searchedstring)).Count();
real example:
var qry = records.Where(x=>x.Name.Contains("sai")).Count();
Below is the simplest code.
int count = records.Count(x => x.Name.StartsWith("hello") || x.About.StartsWith("hello"));

Categories

Resources