Mongodb C# 驱动程序只返回数组中匹配的子文档 [英] Mongodb C# driver return only matching sub documents in array

查看:20
本文介绍了Mongodb C# 驱动程序只返回数组中匹配的子文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这种格式的文档:

I have a document in this format:

{
    _id: ...,
    myArray: [{other: stuff}, {other: stuff}, ...],
    ...
}

我想从 myArray 中的子文档中查找与某些内容匹配的元素,例如 _id 或字段值.

I want to find elements that match certain things, like the _id or fields value from the sub-documents in myArray.

我想返回文档,但使用过滤后的 MyArray,其中仅存在匹配的子文档.

I want to return the documents, but with a filtered MyArray where only the matching sub-documents are present.

我尝试进行投影并包含这样的匹配元素:

I tried to do a projection and include the matched elements like this:

_mongoContext.myDocument
    .Find(x => x.id == id & x.myArray.Any(y => myList.Contains(t.other)))
    .Project<myModel>(Builders<myModel>.Projection.Include("myArray.$"))

我认为,这应该只返回在 myArray 中匹配的第一个元素而不是所有文档,这不是我想要的(我希望与查询匹配的所有子文档都存在在返回的文档中).

This, I think, should only return the first element that matched in myArray instead of all documents, which is not what I want (I want all sub-documents that match the query to be present in the returned document).

无论如何它甚至没有工作,我收到一个位置投影与查询文档不匹配错误.也许是因为我没有使用 FindOne?

And anyway it did not even work, I'm getting a positional projection does not match the query document error. Maybe it's because I'm not using FindOne?

无论如何,我怎样才能实现我的目标?(见粗体问题)

In any case, how can I achieve what I'm looking for? (See question in bold)

推荐答案

通常你需要使用 $filter 在聚合框架中过滤嵌套数组.但是,使用 MongoDB .NET 驱动程序和 IQueryable 接口可以更轻松地实现这一点.

Typically you need to use $filter in Aggregation Framework to filter nested array. However there's an easier way to achieve that using MongoDB .NET Driver and IQueryable interface.

考虑最简单的模型:

public class MyModel
{
    public string _id { get; set; }
    public IEnumerable<MyNestedModel> myArray { get; set; }
}

public class MyNestedModel
{
    public string other { get; set; }
}

以及以下数据:

var m = new MyModel()
{
    _id = "1",
    myArray = new List<MyNestedModel>() {
        new MyNestedModel() {  other = "stuff" },
        new MyNestedModel() { other = "stuff" },
        new MyNestedModel() { other = "stuff2" } }
};

Col.InsertOne(m);

您可以简单地在您的集合上调用 .AsQueryable(),然后您可以编写 LINQ 查询,该查询将由 MongoDB 驱动程序转换为 $filter,尝试:

you can simply call .AsQueryable() on your collection and then you can write LINQ query which will be translated by MongoDB driver to $filter, try:

var query = from doc in Col.AsQueryable()
            where doc._id == "1"
            select new MyModel()
            {
                _id = doc._id,
                myArray = doc.myArray.Where(x => x.other == "stuff")
            };

var result = query.ToList();

或者,您可以将 $filter 部分编写为原始字符串,然后使用 .Aggregate() 方法.使用这种方法您不必映射"所有属性,但缺点是您正在失去类型安全,因为这只是一个字符串,请尝试:

Alternatively you can write $filter part as a raw string and then use .Aggregate() method. Using this approach you don't have to "map" all properties however the drawback is that you're losing type safety since this is just a string, try:

var addFields = BsonDocument.Parse("{ "$addFields": { myArray: { $filter: { input: "$myArray", as: "m", cond: { $eq: [ "$$m.other", "stuff" ] } }  } } }");

var query = Col.Aggregate()
               .Match(x => x._id == "1")
               .AppendStage<MyModel>(addFields);

$addFields 用于覆盖现有字段.

这篇关于Mongodb C# 驱动程序只返回数组中匹配的子文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆