我正在使用mongodb的c#驱动程序,并希望对我正在创建的Web API使用聚合查询。对于我的聚合查询,我关注的是具有用户名,日期和步骤的配置文件类。我想创建一个查询,选择用户名并获取给定周的总步数,按总步数降序排列。我只想显示他们的用户名和他们的总步数。
当我尝试聚合查询时,我遇到了一些问题,我的某些字段会显示为null。所以,我认为我的查询结构不正确。
我有一个“个人资料”类,我目前正用于我的数据。
[BsonIgnoreExtraElements]
[DataContract]
public class Profile
{
[DataMember]
public string Username { get; set; }
[DataMember]
public DateTime Date { get; set; }
[DataMember]
public uint? Steps { get; set; }
}
我使用以下
创建了一些测试数据,例如配置文件//Test data
for (uint index = 1; index < 20; index++)
{
Profile aprofile = new Profile
{
Username = string.Format("testuser{0}", index),
Date = RandomDay(),
Steps = (index + index + index)*2
};
AddProfile(aprofile);
}
如果我运行代码几次并查询特定用户,我会得到如下数据:
[{"Username":"testuser1","Date":"2014-07-03T00:00:00Z","Steps":6},
{"Username":"testuser1","Date":"2014-07-07T05:00:00Z","Steps":6},
{"Username":"testuser1","Date":"2014-07-17T05:00:00Z","Steps":6},
{"Username":"testuser1","Date":"2014-07-18T05:00:00Z","Steps":6}]
然后,我有几个静态方法来查找我的聚合查询的最早日期和最新日期。
//gets a datetime for the earlist date and time possible for the current week
public static DateTime GetStartOfCurrentWeek()
{
int DaysToSubtract = (int)DateTime.Now.DayOfWeek;
DateTime dt = DateTime.Now.Subtract(TimeSpan.FromDays(DaysToSubtract));
return new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0, 0);
}
//gets a datetime for the latest date and time possible for the current week
public static DateTime GetEndOfCurrentWeek()
{
DateTime dt = GetStartOfCurrentWeek().AddDays(6);
return new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59, 999);
}
我在聚合查询中的尝试如下。
//Here is my aggregation query to get all profiles within a given week,
public IEnumerable<Profile> GetAllProfiles()
{
DateTime StartofWeek = GetStartOfCurrentWeek();
DateTime EndofWeek = GetEndOfCurrentWeek();
var match = new BsonDocument
{{ "$match", new BsonDocument
{{ "Date", new BsonDocument {
{"$gte", StartofWeek},
{"$lt", EndofWeek}
}}}
}};
var group = new BsonDocument
{{"$group",
new BsonDocument
{{ "_id", new BsonDocument
{{"id", "$Username"},
}},
{"Steps", new BsonDocument
{{"$sum", "$Steps"}}
}}
}};
var sort = new BsonDocument
{{"$sort", new BsonDocument
{{"Steps", -1}}
}};
var pipeline = new[] {match, group, sort};
var args = new AggregateArgs { Pipeline = pipeline, OutputMode = AggregateOutputMode.Inline };
// run the aggregation query and get a list of BsonDocuments
IEnumerable<BsonDocument> documents = _profiles.Aggregate(args);
}
但是,我得到的结果是将用户名显示为Null,将日期显示为null。
[{"Username":null,"Date":"0001-01-01T00:00:00","Steps":96},
{"Username":null,"Date":"0001-01-01T00:00:00","Steps":66},
{"Username":null,"Date":"0001-01-01T00:00:00","Steps":24}]
我需要做些什么来获取我的文档数组,以便显示用户名以及我拥有的总步骤(似乎有效)。我不想在查询结果中使用日期。只是那个星期的用户名及其总步数。
答案 0 :(得分:1)
我真的不明白为什么你需要用BSon查询你的mongo。你有你的模型类。您尝试执行的聚合将如下所示:
var result = collection.Aggregate()
.Match(r => r.Date >= StartofWeek && r.Date < EndofWeek)
.Group(r=>r.Username, r=> new {UserName = r.Key, Dates = r.Select(d=>d.Date), Steps = r.Sum(x=>x.Steps)})
.ToList();
注意,你不能得到一个日期,而是它的数组,因此我将它聚合为Dates
。
原因,为什么你没有看到日期和用户名是你不查询它,在你的组声明中我只看到了一些步骤。如果你真的想继续以这种方式查询,你应该将它添加到你的小组阶段,例如:
var group = new BsonDocument
{
{ "_id", new BsonDocument{{"id", "$Username"},
}},
{"Steps", new BsonDocument{{"$sum", "$Steps"}}},
{ "Dates", new BsonDocument{{"$addToSet", "$Date"}} },
{ "Username", new BsonDocument{{"$first", "$Username"}} },
};
通过这种方式,我可以在生成的BsonDocument中看到用户名和日期。
但正如我已经说过的,这种查询Mongo的方式并不是c#
中最好的方法答案 1 :(得分:1)
您的group
阶段有一个缺陷,那就是您没有包含您想要查询的字段。
只需更改group
阶段即可获得所需的字段。
var group = new BsonDocument
{{"$group",
new BsonDocument
{
{ "_id", new BsonDocument
{{"id", "$Username"}}
},
{ "Steps", new BsonDocument
{{"$sum", "$Steps"}}
},
{ "Username", new BsonDocument
{{"$first", "$Username"}} // since the rest of the selected object is groupped, we should give a strategy to pick a $Username, and it is safe to use $first aggregate function here
}
}
}};
如果您对输出结果中的日期不满意,只需添加project
阶段,然后重新整理输出文档。