在数组中聚合C#groupby

时间:2017-09-09 09:43:19

标签: c# mongodb linq aggregation-framework mongodb-csharp-2.0

我有以下结构,我希望聚集在一组电影中,以获取所有演员及其形象。

{
"_id" : 1,
"Title" : "Pirates of the Caribbean: The Curse of the Black Pearl",
"Actors" : [ 
    {
        "Name" : "Johnny Depp",
        "NameInMovie" : "Captain Jack Sparrow",
        "ImageUrl" : "Johnny-Depp.png"
    }, 
    {
        "Name" : "Geoffrey Rush",
        "NameInMovie" : "Captain Hector Barbossa",
        "ImageUrl" : "Geoffrey-Rush.png"
    }, 
    {
        "Name" : "Orlando Bloom",
        "NameInMovie" : "Will Turner",
        "ImageUrl" : "Orlando-Bloom.png"
    }
]

},

{
"_id" : 2,
"Title" : "Pirates of the Caribbean: At World's End",
"Actors" : [ 
    {
        "Name" : "Johnny Depp",
        "NameInMovie" : "Captain Jack Sparrow",
        "ImageUrl" : "Johnny-Depp.png"
    }, 
    {
        "Name" : "Geoffrey Rush",
        "NameInMovie" : "Captain Hector Barbossa",
        "ImageUrl" : "Geoffrey-Rush.png"
    }, 
    {
        "Name" : "Orlando Bloom",
        "NameInMovie" : "Will Turner",
        "ImageUrl" : "Orlando-Bloom.png"
    }
]

}

尝试使用Linq AsQueryable函数获取结果,但不支持:

var actors = Movies
.AsQueryable()
.SelectMany(x => x.Actors)
.GroupBy(x => x.Name)
.Select(a => a.First())
.ToList();

如何使用MongoDB driver2

结果应该像

{"Name" : "Johnny Depp",
"ImageUrl" : "Johnny-Depp.png" }, 
{"Name" : "Geoffrey Rush",
"ImageUrl" : "Geoffrey-Rush.png" }, 
{"Name" : "Orlando Bloom",
"ImageUrl" : "Orlando-Bloom.png" }

解决

var actors = Movies.AsQueryable()
.SelectMany(x => x.Actors)
.GroupBy(x => new Actor { Name = x.Name, ImageUrl = x.ImageUrl })
.Select(x => x.Key)
.ToList();

这提供了以下查询

[{
    "$unwind": "$Actors"
},
{
    "$project": {
        "Actors": "$Actors",
        "_id": 0
    }
},
{
    "$group": {
        "_id": {
            "ImageUrl": "$Actors.ImageUrl",
            "Name": "$Actors.Name"
        }
    }
},
{
    "$project": {
        "_id": "$_id"
    }
}]

1 个答案:

答案 0 :(得分:1)

你很接近,但在$group

中实际选择的属性大部分都缺失了
var results = Movies.AsQueryable()
 .SelectMany( x => x.Actors )
 .GroupBy( x => x.Name )
 .Select( x => new { Name = x.Key, ImgUrl = x.First().ImageUrl })
 .ToArray();

所以.Select()实际上需要与您使用的语法不同的语法。这为您提供了一个序列化的管道:

    [
            {
                    "$unwind" : "$Actors"
            },
            {
                    "$project" : {
                            "Actors" : "$Actors",
                            "_id" : 0
                    }
            },
            {
                    "$group" : {
                            "_id" : "$Actors.Name",
                            "__agg0" : {
                                    "$first" : "$Actors.ImageUrl"
                            }
                    }
            },
            {
                    "$project" : {
                            "Name" : "$_id",
                            "ImgUrl" : "$__agg0",
                            "_id" : 0
                    }
            }
    ],

哪个恕我直言并非完全“最佳”,但这就是你使用LINQ界面所获得的。

交替出现:

var results = Movies.AsQueryable()
 .SelectMany( x => x.Actors )
 .GroupBy( x => new { Name = x.Name, ImgUrl = x.ImageUrl })
 .ToArray();

出现如下:

  [
            {
                    "$unwind" : "$Actors"
            },
            {
                    "$project" : {
                            "Actors" : "$Actors",
                            "_id" : 0
                    }
            },
            {
                    "$group" : {
                            "_id" : {
                                    "Name" : "$Actors.Name",
                                    "ImgUrl" : "$Actors.ImageUrl"
                            }
                    }
            }
    ],

哪个不使用$first,因此不是“完全”相同的东西,但它确实在您的情况下得出相同的结果,因为ImgUrl始终是每个{的相同值Name上的{1}}。