C# MongoDB - 如何仅 select 嵌套属性

C# MongoDB - How to select nested properties only

这就是我的 类 的样子:

public class TestA : MongoDocument
{
    public string ProjectID { get; set; }
    public TestB Content { get; set; }

}

public class TestB
{
    public string Id { get; set; }

    public List<TestC> CustInfo { get; set; }
}

public class TestC
{
    public string Id { get; set; }

    public CustomerComment CustomerComment { get; set; }
}

public class CustomerComment
{
    public string Id { get; set; }
    public string notes { get; set; }
}

我只想 return 基于 TestA.ProjectID && TestC.Id

的 CustomerComment
var projection = Builders<TestA>.Projection
                   .Include(x => x.Content.CustInfo);

var options = new FindOptions<TestA>
{
    Projection = projection
};

var find = await Collection.FindAsync(p => p.ProjectID == "555" && 
                    p.Content.CustInfo.Any(l => l.Id == "123"), options).ConfigureAwait(false);
var result = await find.ToListAsync().ConfigureAwait(false);

这有效,但它会 return 一切。在这种情况下,我只想 return CustomerComments.

所以为了只检索 customerComments,我根据 mongo 的结果进行了另一个查询。下面的代码为我提供了正确的数据,但我宁愿通过数据库进行过滤。

var test = result.SelectMany(x => x.Content.CustInfo.Where(l => l.Id == "123").Select(y => y.CustomerComment)).ToList(); 

我认为Aggregation Query可以满足您查询数据库中的数据并返回所需输出的要求。

  1. $match - 过滤数据。
  2. $unwind - 将数组字段解构为多个文档。
  3. $match - 为 Content.CustInfo.
  4. 过滤数据
  5. $replaceWith - 用新文档替换当前文档进行输出。
db.collection.aggregate([
  {
    $match: {
      "ProjectID": "555",
      "Content.CustInfo.Id": "123"
    }
  },
  {
    $unwind: "$Content.CustInfo"
  },
  {
    $match: {
      "Content.CustInfo.Id": {
        $eq: "123"
      }
    }
  },
  {
    "$replaceWith": "$Content.CustInfo.CustomerComment"
  }
])

Sample Mongo Playground


解决方案 1:使用 AggregateFluent

Pre-requisite: 创建平仓 类.

public class UnwindTestA
{
    public ObjectId _id { get; set; }

    public string ProjectID { get; set; }

    public UnwindTestB Content { get; set; }
}

public class UnwindTestB
{        
    public string Id { get; set; }

    public TestC CustInfo { get; set; }
}
var result = await Collection.Aggregate()
    .Match(
        p => p.ProjectID == "555"
        && p.Content.CustInfo.Any(l => l.Id == "123")
    )
    .Unwind<TestA, UnwindTestA>(x => x.Content.CustInfo)
    .Match<UnwindTestA>(x => x.Content.CustInfo.Id == "123")
    .ReplaceWith<CustomerComment>("$Content.CustInfo.CustomerComment")
    .ToListAsync();

解决方案 2:使用 BsonDocument

有时,使用 AggregateFluent 编写查询非常复杂。您可以使用转换为 BsonDocument.

的 MongoDB 查询
BsonDocument[] aggregate = new BsonDocument[]
{
    new BsonDocument("$match",
        new BsonDocument
            {
                { "ProjectID", "555" },
                { "Content.CustInfo.Id", "123" }
            }),
    new BsonDocument("$unwind", "$Content.CustInfo"),
    new BsonDocument("$match",
        new BsonDocument("Content.CustInfo.Id",
            new BsonDocument("$eq", "123"))),
    new BsonDocument("$replaceWith", "$Content.CustInfo.CustomerComment")
};

var result = await Collection.Aggregate<CustomerComment>(aggregate)
    .ToListAsync();

Output