过滤mongodb子元素

时间:2019-07-18 20:26:26

标签: c# .net mongodb

我有一个父元素列表,需要根据子列表中的结构进行过滤。

这是数据结构

"items": [
    {
        "id": "6691e62b-90as-43b2-k1l3-2fbf039295b5",
        "details": {
            "zone": {
                "id": "cc07de83-3m21-1pp1-a123-a98bd8fb5fb8",
                "name": "TestName",
            }
        },
    }
]
var findresult = collection(f => f.items.Any(fb => fb.details.zone.name == "TestName")).ToList();

期望仅返回具有匹配区域名称的项目,但我只返回数据库中的所有内容

1 个答案:

答案 0 :(得分:0)

要获取包含匹配子文档的父文档,您需要使用$elemMatch运算符:

db.Parent.aggregate([
    {
        "$match": {
            "items": {
                "$elemMatch": {
                    "details.zone.name": "second zone"
                }
            }
        }
    }
])

如果只想获取匹配的子文档(项目),则需要$unwind$project,如下所示:

db.Parent.aggregate([
    {
        "$unwind": "$items"
    },
    {
        "$project": {
            "items": "$items",
            "_id": NumberInt("0")
        }
    },
    {
        "$match": {
            "items.details.zone.name": "second zone"
        }
    }
])

这是上面查询生成的c#代码。代码使用MongoDB.Entities为简洁起见。查询部分与官方驱动程序相同。只需使用collection.AsQueryable()代替DB.Queryable<Parent>()

using MongoDB.Driver.Linq;
using MongoDB.Entities;
using System;
using System.Linq;

namespace StackOverflow
{
    public class Program
    {
        public class Parent : Entity
        {
            public Item[] items { get; set; }
        }

        public class Item
        {
            public string id { get; set; }
            public Detail details { get; set; }
        }

        public class Detail
        {
            public string id { get; set; }
            public Zone zone { get; set; }
        }

        public class Zone
        {
            public string id { get; set; }
            public string name { get; set; }
        }

        private static void Main(string[] args)
        {
            new DB("test");

            (new[] {
                new Parent {
                items = new[]
                {
                    new Item
                    {
                        id = Guid.NewGuid().ToString(),
                        details = new Detail
                        {
                            id = Guid.NewGuid().ToString(),
                            zone = new Zone
                            {
                                id = Guid.NewGuid().ToString(),
                                name = "first zone"
                            }
                        }
                    }
                }
            },
                new Parent {
                items = new[]
                {
                    new Item
                    {
                        id = Guid.NewGuid().ToString(),
                        details = new Detail
                        {
                            id = Guid.NewGuid().ToString(),
                            zone = new Zone
                            {
                                id = Guid.NewGuid().ToString(),
                                name = "second zone"
                            }
                        }
                    }
                }
            }
            }).Save();

            //get all Parent entities that have 'second zone'
            var result = DB.Queryable<Parent>()
                           .Where(p => p.items.Any(i => i.details.zone.name == "second zone"))
                           .ToArray();

            //get only items that have 'second zone'
            var items = DB.Queryable<Parent>()
                          .SelectMany(p => p.items)
                          .Where(i => i.details.zone.name == "second zone")
                          .ToArray();
        }
    }
}

评论后更新: 为了获得父项并过滤出不匹配的子项,您需要一个$elemMatch的投影台,如下所示:

db.Parent.find({
    "items": {
        "$elemMatch": {
            "details.zone.name": "second zone"
        }
    }
}, {
    "_id": NumberInt("1"),
    "items": {
        "$elemMatch": {
            "details.zone.name": "second zone"
        }
    }
})

c#MongoDB。实体:

 var result = DB.Find<Parent>()
                .Match(p => p.items.Any(i => i.details.zone.name == "second zone"))
                .Project(b =>
                         b.Include(p => p.ID)
                          .ElemMatch(p => p.items, i => i.details.zone.name == "second zone"))
                .Execute();

c#官方驱动程序:

var projection = Builders<Parent>.Projection
                                 .Include(p => p.ID)
                                 .ElemMatch(p => p.items, i => i.details.zone.name == "second zone");

var result = collection.Find(p => p.items.Any(i => i.details.zone.name == "second zone"))
                       .Project(projection)
                       .ToList();