如何使用 C# 控制 MongoDb 中的投影定义

How to control the projection definition in MongoDb using C#

我有一个这样的域 class。

public class Thing
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Dictionary<string, string> Stuff { get; set; }
}

我正在使用以下方法从我的数据库中检索它。

return await _db.Things
    .Find(x => x.Name == name)
    .SingleOrDefaultAsync(token);
    

我注意到,可能有大量不必要的数据,所以我使用了这样的投影。

ProjectionDefinition<Thing> projection = Builders<Thing>
    .Projection
    .Include(a => a.Id)
    .Include(a => a.Name);

BsonDocument projected = await _dbContext.Things
    .Find(x => x.Name == name)
    .Project(projection)
    .SingleOrDefaultAsync(token);

这行得通,但自然会削减 所有 词典内容。我想更改投影的定义以包括该字段,但对构成元素进行过滤。假设我只想引入以 duck 开头的所述字典的键。尝试可能是这样的。

ProjectionDefinition<Thing> projection = Builders<Thing>
    .Projection
    .Include(a => a.Id)
    .Include(a => a.Name)
    .Include(a => a.Stuff.Where(b => b.Key.StartsWith("duck")));

导致异常如下。

System.NotSupportedException: The expression tree is not supported: {document}{configuration}

鉴于我对 MongoDb 的无知,我不知道我是应该添加一些东西,删除一些东西还是一起忘记这个想法。我还尝试使用原始类型,以便能够以这种方式过滤内容,但我得到的唯一解决方案是 post-fetch,基本上是调取检索到的数据。我想降低从数据库到我的服务的负载。

Thing projected = await _dbContext.Things
    .Find(x => x.Name == name)
    .Project<Thing>(projection)
    .SingleOrDefaultAsync(token);

它是否可行,如果可行,如何(或至少 google 做什么)?

努力证明:, general operations, tutorials, wrong answers 等等。它可能就在某处,但我没能找到它(或者如果找到了我也认不出来)。

最后,我陷入了以下困境——上帝原谅我,因为我不知道自己在做什么。这是完全正确的方向还是一群疯狂的驴子会为此咬我的后腰?!

ProjectionDefinition<Thing, Thing> wtf = Builders<Thing>.Projection
    .Expression(a => new Thing
    {
        Id = a.Id,
        Name = a.Name,
        Stuff = a.Stuff
            .Where(b => b.Key == scope)
            .ToDictionary(b => scope, b => b.Value)
    });

这是 mongo shell 查询 MongoDB v4.2.8.

考虑这个输入文档:

{
        "_id" : 1,
        "name" : "john",
        "stuff" : {
                "mycolor" : "red",
                "fruit" : "apple",
                "mybook" : "programming gems",
                "movie" : "star wars"
        }
}

目标是 投影 namestuff 字段,但 stuff 只有以 [=17= 开头的字段名称].

聚合查询:

db.test.aggregate([
  { 
      $project: { 
          _id: 0, 
          name: 1, 
          stuff: { 
              $filter: { 
                  input: { $objectToArray: "$stuff" }, 
                  as: "stf", 
                  cond: { $regexMatch: { input: "$$stf.k" , regex: "^my" } }
              }
          }
      }
  },
  { 
      $addFields: { stuff: { $arrayToObject: "$stuff" } } 
  }
])

并且,预计输出:

{
        "name" : "john",
        "stuff" : {
                "mycolor" : "red",
                "mybook" : "programming gems"
        }
}