We have an database with an this structure:
public partial class ChartData
{
public int Id { get; set; }
public DateTime Timestamp { get; set; }
public string Function { get; set; }
public int Duration { get; set; }
public bool IsError { get; set; }
}
Now we want to group the entries of this database by Timestamp.ToShortDateString() and then count the entries belonging to this date.
So for example we have:
2019-06-04 11:54:02,135,someFunction,30,False,
2019-06-04 11:55:03,135,someFunction,230,False,
2019-06-04 11:56:03,150,someFunction,4,True,
2019-06-05 11:54:03,230,someFunction,46,False,
2019-06-05 11:55:03,230,someFunction,46,False,
And I want this result:
{date: 2019-06-04, rows: 3}
{date: 2019-06-05, rows: 2}
public List <LogFileDTO> GetLogFilesData()
{
var items = db.ChartDatas.GroupBy(x = > new {
x.Timestamp.ToShortDateString
}).Select(x = > new LogFileDTO {
date = x.Timestamp.First(),
rows = x.Count ?
}).ToList();
}
So I do not really know how to group this input by date and then count the rows of each group.
You simply need to group on the Date property of the TimeStamp and then project using Select on the Key of each IGropuing and Count like below :
var items = db.ChartDatas.GroupBy(x => x.Timestamp.Date) // group only on Date
.Select(x => new LogFileDTO
{
Date = x.Key.ToShortDateString(),
Rows = x.Count()
}).ToList();
Key will contain only date part of DateTime object and Count() will tell the number of rows for that date in the group.
Hope it helps!
Related
I have a product model class with many versions childs:
public class Product {
public int Id {
get;
set;
}
public string Name {
get;
set;
} = "";
public List <Version> Versions {
get;
set;
} = new List <Version> ();
}
public class Version {
public int Id {
get;
set;
}
public string Name {
get;
set;
} = "";
public DateTime ReleaseDate {
get;
set;
} = new DateTime();
}
I want to filter by a child property: releasedate:
var releaseDateFrom = DateTime.ParseExact("20110720", "yyyyMMdd", CultureInfo.InvariantCulture);
var products = ProductRepository.GetAll();
List <ProductDto> list;
list = products.Where(
p => (p.Name!.StartsWith("p") &&
p.Name!.Length > 0) &&
GetReleaseDateFromVersion(p.Versions.OrderBy(p => p.ReleaseDate).LastOrDefault()) > releaseDateFrom
).Select(p =>
new ProductDto {
Id = p.Id,
Name = p.Name,
LatestVersionDate = GetReleaseDateFromVersion(p.Versions.OrderBy(p => p.ReleaseDate).LastOrDefault())
}).ToList();
DateTime GetReleaseDateFromVersion(Version v) => v == null ? new DateTime() : v.ReleaseDate;
list.ForEach(p => Console.WriteLine("{0} {1}", p.Name, p.LatestVersionDate));
The result output shows that the filter date > 20 July 2022 does not work:
product 1 11/20/2013 00:00:00
product 2 06/20/2013 00:00:00
Product 2 should not be listed.
What am I doing wrong? Any suggestions how to fix this query?
The code can be run here: https://dotnetfiddle.net/esRdOg
Edit after comment from #SergeySosunov
As #SergeySosunov correctly noted: My filter date was wrong. The above code works as expected.
I have a list of the following class:
public class Data
{
public string Sector { get; set; }
public string Company { get; set; }
public string Branch { get; set; }
public string Category { get; set; }
public string Item { get; set; }
public string Currency { get; set; }
public int Year { get; set; }
public int Quarter { get; set; }
public int Month { get; set; }
public double Amount { get; set; }
}
With the date range given by the user, I am bringing data on year and month basis. However there is no data for some year and month in the given date range.
var dateRange = new List<DateTime>();
for (DateTime date = Report.Parameter.BeginDate; date <= Report.Parameter.EndDate; date.AddMonths(1))
{
dateRange.Add(new DateTime(date.Year, date.Month, 1));
}
For each year and month in the given date range, I want the Data object to come with a Amount column of 0 (zero).
This data should be added once for each Sector, Company, Branch and Category columns.
Example:
How do I do this with linq?
If you really need to use Linq, it would look like this:
public void MyFunction(List<Data> userData)
{
var beginDate = DateTime.Today;
var endDate = DateTime.Today.AddYears(2);
var monthsApart = 12 * (beginDate.Year - endDate.Year) + beginDate.Month - endDate.Month;
var dateRange = Enumerable.Range(0, monthsApart).Select(offset => beginDate.AddMonths(offset));
var difference = dateRange.Where(item => !(userData.Any(uData => uData.Year == item.Year && uData.Month == item.Month)));
userData.AddRange(difference.Select(date => new Data() {Year = date.Year, Month = date.Month, Amount = 0}));
}
This is just an example. You need to add your logic, where it is needed.
You mentioned This data should be added once for each Sector, Company, Branch and Category columns
If you want to do this, you have to call
userData.AddRange(difference.Select(date => new Data() {Year = date.Year, Month = date.Month, Amount = 0}));
as many times as you have combinations of Sector, Company, Branch and Category.
I hope this helps to understand and my explanation is not too complex.
My RowMultiplevaluw table is
public class RowMultipleValues
{
public int ID { get; set; }
public String Year{ get; set; }
public string country { get; set; }
public decial Admin { get; set; }
public decimal Finance { get; set; }
public virtual ICollection<UsedAmount> UsedAmount { get; set; }
}
My used amount table is
public class UsedAmount
{
public int ID { get; set; }
public string Year{ get; set; }
public string country { get; set; }
public decial UsedAmount { get; set; }
public int RowMultipleValues ID { get; set; }
Public virtual RowMultibleValue RowMultibleValue { get; set; }
}
My query is
var query = from mtv in context.multiplerowvaluetable
join usd in dbcontext.usedtsble on mtv.year equal usd.year group g by mtv.country into g
select new { country =g.key,sumadmincolumn =g.sum(Admin),sumfinancecolumn = g.sum(finance) }).tolist();
Result which I want is
ID Year Country Admin. UsedAdmin Finance UsedFinance
1. 2017 USA 100 50 200 300
2. 2017 China 300 300 500 400
Total. 400 350 700 700
Please help me my model design and query for result.Thank.
So you want to join every MultipleValue with the UsedAmount on equal year value. Then group the result into groups of joined items with same country. Finally from every group create one object with the country, the sum of all Admin values and the sum of all finance values.
// first join the two collections on same year.
// we only need properties Country, Admin, Finance:
var result = myDbContext.MultipleRowValueTable.Join(myDbContext.UsedAmountTable,
multipleRow => multipleRow.Year, // from every multipleRow take the year
usedAmount => usedAmount.Year, // from every usedAmount take the year
(multipleRow, usedAmount) => new // when they match make a new object
{
Country = multipleRow.Country,
Admin = multipleRow.Admin,
UsedAdmin = usedAmount.Admin,
Finance = multipleRow.Finance,
UsedFinance = usedAmount.Finance,
})
// group the elements from this join table into groups with same Country
.GroupBy(joinedItem => joinedItem.Country, // all items in the group have this Country
joinedItem => new // the elements of the group
{
Admin = joinedItem.Admin,
UsedAdmin = joinedItem.UsedAdmin,
Finance = joinedItem.Finance,
UsedFinance = joinedItem.UsedFinance,
})
// finally: from every group take the Key (which is the Country)
// and the sum of the Admins and Finances in the group
.Select(group => new
{
Country = group.Key,
SumAdminColumn = group
.Select(groupElement => groupElement.Admin)
.Sum(),
... // others are similar
});
// from every group take the elements and sum the properties
.Select(group => new
{
Id = multipleRowValue.Id,
Year = multipleRowValue.Year,
Country = multipleRowValue.Country,
}
I am new to RavenDB and I am trying to query the document model below with the index below. The index is almost working as desired, except now I need to only include the most recent status for a date in the total. For example, a client could have multiple import statuses for a date, but only the last status should be counted in the resulting totals.
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
public IList<ImportStatusMessage> ImportStatuses { get; set; }
}
public class ImportStatusMessage
{
public DateTime TimeStamp { get; set; }
public ImportStatus Status { get; set; }
}
public enum ImportStatus
{
Complete,
Running,
Failed,
Waiting,
NoReport
}
I am using the following index:
public class Client_ImportSummaryByDate : AbstractIndexCreationTask<Client, ImportSummary>
{
public Client_ImportSummaryByDate()
{
Map = clients => from client in clients
from status in client.ImportStatuses
select new
{
status.Status,
Date = status.TimeStamp.Date,
Count = 1
};
Reduce = results => from result in results
group result by new { result.Status, result.Date }
into g
select new
{
g.Key.Status,
g.Key.Date,
Count = g.Sum(x => x.Count)
};
}
}
public class ImportSummary
{
public ImportStatus Status { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
Can this be accomplished with an index? Do I need a different approach to solve this problem?
Instead of:
from status in client.ImportStatuses
Consider:
let status = client.ImportStatuses.Last()
If they might be out of order in the list, you could do:
let status = client.ImportStatuses.OrderBy(x => x.TimeStamp).Last()
You could also use First instead of Last if they were so ordered that way.
Any of these would index just a single status per client. If instead you mean that you want multiple status, but only the last on any given date, you could do:
Map = clients => clients.SelectMany(x => x.ImportStatuses, (x, y) => new {x.Id, y.Status, y.TimeStamp})
.GroupBy(x => new {x.Id, x.TimeStamp.Date})
.Select(g => g.OrderBy(x => x.TimeStamp).Last())
.Select(x => new
{
x.Status,
x.TimeStamp.Date,
Count = 1
});
All of this would be in the map part of the index, since the list is self-contained in each document.
I have 2 classes as below. If I had a generic list of class Schedule like List how would I write a LINQ query such that I can get all items within this List where SourceId matches 1,2,3...X and StartTime > some date time and then I want to return top 3 elements for each SourceId (ie: group by SourceId)
Since this List would be containing huge number of records, I want to write the most efficient LINQ query
Also I want the final shape of result to be in the form of List
public class Source
{
public int SourceId { get; set; }
public string Name { get; set; }
}
public class Schedule
{
public int SourceId { get; set; }
public Source Source { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
after hours of googling:
var result = r.ScheduleList.
Where(s => sourceIdIntArray.Contains(s.SourceId) &&
s.StartTime >= new DateTime(2011, 09, 20)).
GroupBy(s => s.SourceId).
SelectMany(g => g.OrderBy(s => s.StartTime).
Take(3)).
ToList();
Assuming that:
no 2 sources have the same source Id
you want the top 3 elements ordered by StartTime
you're ok with having a List<KeyValuePair<int,Schedule>> as your result (top 3 grouped by Source Id and still returned as a list)
IEnumerable<Schedule> schedules;
DateTime someDateTime; // date time used for comparison
IEnumerable<int> sourceIds; // required matching source Ids
schedules.OrderBy(x=>x.StartTime)
.Where(x => x.StartTime > someDateTime)
.GroupBy(x=>x.Source.SourceId)
.Where(x=>sourceIds.Contains(x.Key))
.ToDictionary(x=>x.Key, x=>x.Take(3))
.ToList()