简体   繁体   English

MongoDB C# 驱动程序 - 如何在 .NET 中对加入的集合强制投影?

[英]MongoDB C# Driver - how to enforce projection on the joined collection in .NET?

Here's the code:这是代码:

ProjectionDefinition<Accountant> projDefAccountant = Builders<Accountant>.Projection
                    .Include(x => x.Id)
                    .Include(x => x.Name);

ProjectionDefinition<Client> projDefClient = Builders<Client>.Projection
                    .Include(c => c.Name)
                    .Include(c => c.Address)
                    .Include(c => c.Occupation);

IMongoCollection<Accountant> collection = mongoDatabase.GetCollection<Accountant>("accountants");
IMongoCollection<Client> foreignCollection = mongoDatabase.GetCollection<Client>("clients");

                var results = collection.Aggregate()
                    .Project<Accountant>(projDefAccountant)
                    .Lookup<Accountant, Client, Accountant>(
                        foreignCollection: foreignCollection,
                        localField: ac => ac.BestClientsIds,
                        foreignField: c => c.Id,
                        @as: ac => ac.MyClients
                    ).ToList().AsQueryable();

I'm able to use the first projection "projDefAccountant" to limit what fields I want out of the "accountants" collection.我可以使用第一个投影"projDefAccountant"来限制我想要从"accountants"集合中删除哪些字段。 Is there a way to enforce the "projDefClient" projection on the joined "clients" collection so that the join doesn't return all the fields but only those specified in the "projDefClient" ?有没有办法在加入的"clients"集合上强制执行"projDefClient"投影,以便加入不会返回所有字段,而只返回"projDefClient"指定的字段? Thx.谢谢。

You can use $lookup with custom pipeline and your aggregation could look like this:您可以将$lookup 与自定义管道一起使用,您的聚合可能如下所示:

db.accountants.aggregate([
    { "$project" : { "_id" : 1, "Name" : 1, BestClientsIds: 1 } }, 
    { 
        "$lookup" : { 
            "from" : "clients", 
            "let" : { "best_client_ids" : "$BestClientsIds" }, 
            "pipeline" : [
                { "$match" : { "$expr" : { "$in" : [ "$_id", "$$best_client_ids"] } } }, 
                { "$project": { Name: 1, Address: 1, Occupation: 1} }
            ], 
            as: "MyClients"}
    }    
]);

Mongo Playground蒙戈游乐场

In C# there's one overloaded version of .Lookup which allows you to run that method in an almost strongly-typed way.在 C# 中有一个.Lookup的重载版本,它允许您以几乎强类型的方式运行该方法。 Here's the signature:这是签名:

IAggregateFluent<TNewResult> Lookup<TForeignDocument, TAsElement, TAs, TNewResult>(
        IMongoCollection<TForeignDocument> foreignCollection,
        BsonDocument let,
        PipelineDefinition<TForeignDocument, TAsElement> lookupPipeline,
        FieldDefinition<TNewResult, TAs> @as,
        AggregateLookupOptions<TForeignDocument, TNewResult> options = null)
        where TAs : IEnumerable<TAsElement>;

You can modify projDefAccountant so that it includes BestClientsIds field:您可以修改projDefAccountant以使其包含BestClientsIds字段:

ProjectionDefinition<Accountant> projDefAccountant = Builders<Accountant>.Projection
            .Include(x => x.Id)
            .Include(x => x.Name)
            .Include(x => x.BestClientsIds);

Then it's easier to specify let and $match phases as BsonDocument however the rest stays strongly-typed:然后将let$match阶段指定为BsonDocument更容易,但其余部分保持强类型:

var filter = new BsonDocumentFilterDefinition<Client>(BsonDocument.Parse("{ $expr: { $in: [ '$_id', '$$ids' ] } }"));

PipelineDefinition< Client, Client> pipeline = new PipelineStagePipelineDefinition<Client, Client>(
    new IPipelineStageDefinition[]
    {
        PipelineStageDefinitionBuilder.Match(filter),
        PipelineStageDefinitionBuilder.Project<Client, Client>(projDefClient),
    });

ExpressionFieldDefinition<Accountant, Client[]> fieldDef 
    = new ExpressionFieldDefinition<Accountant, Client[]>(f => f.MyClients);

var letDef = BsonDocument.Parse("{ ids: '$BestClientsIds' }");


var results = collection.Aggregate()
    .Project<Accountant>(projDefAccountant)
    .Lookup<Client, Client, Client[], Accountant>(
        foreignCollection: foreignCollection,
        let: letDef,
        lookupPipeline: pipeline,
        @as: fieldDef
    ).ToList().AsQueryable();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM