我有一个集合,存储有关alert 器的信息—通知.我需要通过(long)userid获取汇总的用户统计数据:
- 拥有的alert 器计数;
- 订阅数;
- 用户负责的alert 器计数
Siren文档 struct (仅限提问的必要字段):
{
"_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;}
}
当其中一个字段缺失时,将捕获异常:
发生异常:NTFS/MongoDB. Driver. MongoCommandException 发生类型为'MongoDB. Driver. MongoCommandException'的异常, System.Private.CoreLib.dll,但未在用户代码中处理:'命令 聚合失败:聚合过程中的PlanExecutor错误::导致 ::$in需要一个数组作为第二个参数,find:missing."
更新.固定方法:
public async Task<UserStatistics> Get(long userId)
{
var query = sirens.AsQueryable()
.Where(_sirena => _sirena.OwnerId == userId
|| _sirena.Listener.Any(x => x == userId)
|| _sirena.Responsible.Any(x => x == userId))
.GroupBy(keySelector: x => true,
resultSelector: (_, _sirens) => new UserStatistics
{
SirenasCount = _sirens.Sum(x => x.OwnerId == userId ? 1 : 0),
Subscriptions = _sirens.Sum(_sirena => (_sirena.Listener ?? new long[] { }).Contains(userId) ? 1 : 0),
Responsible = _sirens.Sum(_sirena => (_sirena.Responsible ?? new long[] { }).Contains(userId) ? 1 : 0)
})
.FirstOrDefaultAsync();
return await query;
}
感谢永顺3<
P.S. MongoDB.Driver 2.24也提供了翻译some_array is Array
的行为,但不幸的是它被bug了.第is Array
章:
"$cond": {
"if": {
"$and": [{
"$or": [{
"$eq": ["$some_array._t", "Array"]
}, {
"$and": [{
"$isArray": "$some_array._t"
}, {
"$in": ["Array", "$some_array._t"]
}
...
在我的情况下,MongoDB v.7.0.6它不正常工作.但如果我们改变"$eq": ["$some_array._t", "Array"]
—{"$isArray": "$some_array"}
,那么它将工作>