我有一个集合,其中存储有关警报器的信息 - 通知。我需要通过(长)用户 ID 获取汇总的用户统计信息:
Siren 文档结构(仅限问题所需字段):
{
"_id": ObjectId( "65fc94593273fc2ab6ff8960"),
"ownerid": NumberLong( "99999999"),
"listener": [
NumberLong( "11111111"),
NumberLong( "00000000")
],
"responsible": [
NumberLong( "11111111")
]
}
经过 2 天的努力,我通过 JS 提出了工作请求
db.sirens.aggregate([
{
"$match": {
"$or": [
{ "ownerid": userId },
{ "listener": userId },
{ "responsible": userId }
]}},
{
"$group": {
"_id": null,
"owner": { "$sum": { "$cond": [{ "$eq": ["$ownerid", userId ] }, 1, 0] }},
"responsible": { "$sum": { "$cond": [{ "$and": [
{ "$ne": ["$responsible", null] },
{ "$isArray": "$responsible" },
{ "$in": [userId, "$responsible"] }
] }, 1,0 ] }}
,"listener": { "$sum": { "$cond": [{ "$and": [
{ "$ne": ["$listener", null] },
{ "$isArray": "$listener" },
{ "$in": [userId, "$listener"] }
] }, 1,0 ] }}
}
}
]);
但是这里有一个我无法解决的问题。字段 “listener” 和 “responsible” 可能会丢失。在 JS 中,这个条件:
{ "$isArray": "$responsible" },
可以处理这种情况。但我不能在 C# 中做同样的事情。
这是我到目前为止得到的代码:
var query = sirens.AsQueryable<SirenRepresentation>()
.Where(_sirena => _sirena.OwnerId == userId
|| (_sirena.Listener != null && _sirena.Listener.Any(x => x == userId))
|| (_sirena.Responsible != null && _sirena.Responsible.Any(x => x == userId)))
.GroupBy(s => true)
.Select(g => new UserStatistics
{
SirenasCount = g.Sum(_siren => _siren.OwnerId == userId ? 1 : 0),
Subscriptions = g.Sum(_siren => (_siren.Listener != null && _siren.Listener.Contains(userId)) ? 1 : 0),
Responsible = g.Sum(_siren => (_siren.Responsible != null && _siren.Responsible.Contains(userId)) ? 1 : 0)
});
public class SirenRepresentation
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("ownerid"), BsonRepresentation(BsonType.Int64)]
public long OwnerId { get; set; }
[BsonRepresentation(BsonType.Int64)]
[BsonElement("listener")]
public long[] Listener { get; set; } = [];
[BsonRepresentation(BsonType.Int64)]
[BsonElement("responsible")]
public long[] Responsible { get; set; } = [];
[BsonElement("requests")]
//...
}
public class UserStatistics{
public int SirenasCount{get;set;}
public int Subscriptions{get;set;}
public int Responsible{get;set;}
}
当其中一个字段丢失时,会捕获异常:
发生异常:CLR/MongoDB.Driver.MongoCommandException 类型“MongoDB.Driver.MongoCommandException”的异常发生在 System.Private.CoreLib.dll 但未在用户代码中处理:'Command 聚合失败:聚合期间 PlanExecutor 错误 :: 导致 :: $in 需要一个数组作为第二个参数,发现:丢失。'
由于您的
Listener
和 Responsible
字段可能丢失,您可以使用以下方式为该字段提供默认值:
(_siren.Listener ?? new long[] { })
因此,转换为MongoDB查询时,相当于
{ "$ifNull" : ["$responsible", []] }
完整查询:
var query = sirens.AsQueryable<SirenRepresentation>()
.Where(_siren => _siren.OwnerId == userId
|| (_siren.Listener != null
&& (_siren.Listener ?? new long[] { }).Any(x => x == userId))
|| (_siren.Responsible != null
&& (_siren.Responsible ?? new long[] { }).Any(x => x == userId)))
.GroupBy(s => true)
.Select(g => new UserStatistics
{
SirenasCount = g.Sum(_siren => _siren.OwnerId == userId ? 1 : 0),
Subscriptions = g.Sum(_siren => (_siren.Listener != null
&& (_siren.Listener ?? new long[] { }).Contains(userId)) ? 1 : 0),
Responsible = g.Sum(_siren => (_siren.Responsible != null
&& (_siren.Responsible ?? new long[] { }).Contains(userId)) ? 1 : 0)
});