如何在 C# 中的 MongoDB 查询中将 "aggregate" 与 "project" 一起使用?

How to use "aggregate" with "project" in MongoDB query in C#?

环境:

MongoDB.Driver (2.8.1);

Microsoft.NETCore.App (3.0.0-preview7-27912-14);

语言:C#

我在 MongoDB 中有以下存储结构,在一个名为:"Revendas":

的集合中
...
{
    "_id" : ObjectId("5cd0825f92225e4f1179f3b8"),
    "Codigo" : NumberLong(0),
    "Nome" : "Revenda com dois clientes",
    "CPF" : "string",
    "CNPJ" : "string",        
    "Clientes" : [ 
        {
            "Codigo" : "1",
            "Nome" : "Primeiro cliente da revenda 5cd0825f92225e4f1179f3b8",
            "CPF" : "string",
            "CNPJ" : "string",
            "Tokens" : [ 
                {                        
                    "Token" : "bd2b0f0734b3977ebfd56b6965fbdf9bff17f1e6",
                    "Geracao" : ISODate("2019-05-03T17:27:30.678-03:00"),
                    "Revogacao" : ISODate("2019-05-03T17:28:58.858-03:00")
                }
            ]
        }, 
        {
            /*This is the block I need to return*/
            "Codigo" : "2",
            "Nome" : "Segundo cliente da revenda 5cd0825f92225e4f1179f3b8",
            "CPF" : "string",
            "CNPJ" : "string",
            "Tokens" : [ 
                {
                    /* This is the field where I will do the research */
                    "Token" : "671bcaf806405e5d55419746a1b320cc729558fb",
                    "Geracao" : ISODate("2019-05-06T09:29:07.928-03:00"),
                    "Revogacao" : ISODate("2022-05-06T09:29:07.928-03:00")
                }
            ]
        }
    ]
}
...

我想搜索客户端令牌集合,return 只搜索回答查询的客户端。 我能够直接在 mongodb:

中执行查询
db.Revendas.aggregate([
    { $unwind :'$Clientes'},
    { $match : {'Clientes.Tokens.Token': '671bcaf806405e5d55419746a1b320cc729558fb' }},
    { 
        $project : {
            Codigo: "$Clientes.Codigo", 
            Nome : '$Clientes.Nome', 
            CNPJ : '$Clientes.CNPJ',
            CPF: '$Clientes.CPF',
            Tokens : '$Clientes.Tokens'       
        } 
    }
])

上次查询return我需要的数据:

{
    "_id" : ObjectId("5cd0825f92225e4f1179f3b8"),
    "Codigo" : "2",
    "Nome" : "Segundo cliente da revenda 5cd0825f92225e4f1179f3b8",
    "CNPJ" : "string",
    "CPF" : "string",
    "Tokens" : [ 
        {
            "Token" : "671bcaf806405e5d55419746a1b320cc729558fb",
            "Geracao" : ISODate("2019-05-06T09:29:07.928-03:00"),
            "Revogacao" : ISODate("2022-05-06T09:29:07.928-03:00")
        }
    ]
}

问题是,如何将此查询转换为 C# mongodb 驱动程序?

我的尝试是:

string tokenpesquisa = "";

var agg = Database.GetCollection<RevendaCliente>("{'Clientes.Tokens.Token': '" + tokenpesquisa + "'}").Aggregate();

var project = agg.Project(o => new {
    Codigo = o.Codigo,
    Nome = o.Nome,
    CNPJ = o.CNPJ,
    CPF = o.CPF,
    Tokens = o.Tokens
});

var result = project.ToListAsync().Result;

但数据未按预期return编辑。


以下是用户@mickl 建议的解决我问题的代码片段:

CollRevendas = Database.GetCollection<Revenda>("Revendas");

var query = CollRevendas.Aggregate()
 .Unwind("Clientes")
 .Match(new BsonDocument() { { "Clientes.Tokens.Token", "" + tokenpesquisa + "" } })
 .Project<RevendaCliente>(new BsonDocument()
     {
        { "_id", 0 },
        { "Codigo", "$Clientes.Codigo" },
        { "Nome", "$Clientes.Nome" },
        { "CNPJ", "$Clientes.CNPJ" },
        { "CPF", "$Clientes.CPF" },
        { "Tokens", "$Clientes.Tokens" }
     });

var doc = query.First();

return doc;

通用方法 GetCollection<T> 将集合名称作为第一个参数。这里最简单的方法是对代表 MongoDB 文档的 BsonDocument 类型进行操作,稍后可以将其反序列化为您的类型:

var col = database.GetCollection<BsonDocument>("Revendas");

var query =  col.Aggregate()
                .Unwind("Clientes")
                .Match(new BsonDocument(){ { "Clientes.Tokens.Token", "671bcaf806405e5d55419746a1b320cc729558fb" } })
                .Project(new BsonDocument()
                    {
                        { "Codigo", "$Clientes.Codigo" },
                        { "Nome", "$Clientes.Nome" },
                        { "CNPJ", "$Clientes.CNPJ" },
                        { "CPF", "$Clientes.CPF" },
                        { "Tokens", "$Clientes.Tokens" }
                    });

var doc = query.First();

您还可以通过引入表示结果的类型来转换聚合结果:

public class Model
{
    public ObjectId Id { get; set; }
    public string Codigo { get; set; }
    public string Nome { get; set; }
    public string CNPJ { get; set; }
    public string CPF { get; set; }
    public TokenModel[] Tokens { get; set; }
}

public class TokenModel
{
    public string Token { get; set; }
    public DateTime Geracao { get; set; }
    public DateTime Revogacao { get; set; }
}

和运行 Project的通用版本:

.Project<Model>(new BsonDocument()
    {
        { "Codigo", "$Clientes.Codigo" },
        { "Nome", "$Clientes.Nome" },
        { "CNPJ", "$Clientes.CNPJ" },
        { "CPF", "$Clientes.CPF" },
        { "Tokens", "$Clientes.Tokens" }
    });