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

查看:26
本文介绍了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).

无论如何它甚至都不起作用,我得到一个 positional projection does not match the query 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天全站免登陆