我有一个集合,存储有关alert 器的信息—通知.我需要通过(long)userid获取汇总的用户统计数据:

  1. 拥有的alert 器计数;
  2. 订阅数;
  3. 用户负责的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"},那么它将工作>

推荐答案

由于您的ListenerResponsible字段可能缺失,您可以为字段提供默认值:

(_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)
    });

Csharp相关问答推荐

有没有办法把+02:00转换成TimeSpan?""

LINQ无法翻译SQLFunctions方法

. NET WireMock拒绝PostAsJsonAsync序列化

在多对多关系上不删除实体

创建临时Collection 最有效的方法是什么?堆栈分配和集合表达式之间的区别?

静态对象构造顺序

在允许溢出的情况下将小数转换为长

.NET SDK包中的官方C#编译器在哪里?

在C#中,非静态接口方法的抽象和虚拟是冗余的吗?

依赖项注入、工厂方法和处置困境

.NET 8 DI GetServices<;对象&>不工作

交替的奇数

在implementationFactory中避免循环依赖

这是否比决定是否使用ConfigureAWait(False)更好?

我应该为C#12中的主构造函数参数创建私有属性吗?

将字符串类型日期输入(yyyy-mm-ddthh:mm:ss)转换为MM/dd/yyyy格式

在.NET Maui中,Flyoutindow/Hamburger菜单可以在shell 之外实现吗?

如何在绑定到数据库的datagridview中向上或向下移动行

C#中COM对象的实际地址

为什么我的UserControl没有加载到我的主窗口中?