MongoDB 将 JS 查询转换为 C# 的问题

问题描述 投票:0回答:1

我有一个集合,其中存储有关警报器的信息 - 通知。我需要通过(长)用户 ID 获取汇总的用户统计信息:

  1. 拥有的警报器数量;
  2. 订阅计数;
  3. 用户负责的警报器计数

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 需要一个数组作为第二个参数,发现:丢失。'

c# mongodb
1个回答
0
投票

由于您的

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)
    });
© www.soinside.com 2019 - 2024. All rights reserved.