Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于点阵列的C#MongoDB排序_C#_Mongodb_Mongodb .net Driver - Fatal编程技术网

基于点阵列的C#MongoDB排序

基于点阵列的C#MongoDB排序,c#,mongodb,mongodb-.net-driver,C#,Mongodb,Mongodb .net Driver,正在开发最新的C#mongodb驱动程序和.NET4.5.1 我想在球员之间进行一些定制的比赛。 假设我有下面的模型 public sealed class PlayerPoints { [BsonId] public ObjectId PlayerId; public DateTime CreateDate; public int Points; public int[] SeasonalPoints; } 我希望能够在特定的季节点索引之间获得球

正在开发最新的C#mongodb驱动程序和.NET4.5.1

我想在球员之间进行一些定制的比赛。 假设我有下面的模型

public sealed class PlayerPoints
{
    [BsonId]
    public ObjectId PlayerId;

    public DateTime CreateDate;

    public int Points;
    public int[] SeasonalPoints;

}
我希望能够在特定的
季节点
索引之间获得球员的排名

例如:

 {PlayerId : someId1, CreateDate : <someCreateDate>, Points : 1000, SeasonalPoints : [100,100,100,100,100,100,100,100,100,100,100]}
 {PlayerId : someId2, CreateDate : <someCreateDate>, Points : 1000, SeasonalPoints : [100,100,100,100,100,100,100,100,50,150,100]}
 {PlayerId : someId3, CreateDate : <someCreateDate>, Points : 1100, SeasonalPoints : [200,100,100,100,100,100,100,100,0,0,300]}
{PlayerId:someId1,CreateDate:,点数:1000,季节点数:[100100100]}
{PlayerId:someId2,CreateDate:,点数:1000,季节点数:[100100100,50150100]}
{PlayerId:someId3,CreateDate:,点数:1100,季节点数:[200100100,0,0300]}
注意这里有10个季节。 我正在搜索一个查询,该查询返回一个按排名排序的玩家列表。排名由提供的索引之间的点的总和设置

如果我查询第九季到第十季的排名,那么someId3是第一名,someId2是第二名,someId1是最后一名。 如果我查询第7-9季的排名,那么someId1是第一名,someId2是第二名,someId3是第三名

我考虑过使用聚合,它会如何影响大约100万个文档的性能,同时这个查询也会被频繁调用

澄清

主要问题是如何构建此查询以生成上述结果,第二个问题是查询将从服务器消耗多少性能


谢谢。

至少,如果服务器所在的计算机与数据库的计算机不同,您将获得更好的服务器性能

另一方面,这可能意味着数据库计算机“可用性”可能会降低,因为它太忙于计算聚合结果。这是应该进行基准测试的事情,因为它随着应用程序的不同而变化,并且时不时地变化

这取决于用户负载、数据量、主机等

至于查询,这里有一个程序,我已经验证了它的实际工作情况:

using System;
using System.Collections.Generic;
using System.Linq;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;

namespace MongoAggregation
{

public sealed class PlayerPoints
{
    public ObjectId Id { get; set; }

    //Note that mongo addresses everything as UTC 0, so if you store local time zone values, make sure to use this attribute
    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
    public DateTime CreateDate { get; set; }

    public int Points { get; set; }
    //note that your model did not allow a player to not participate in some season, so I took the liberty of introducing a new sub document.
    //It is better to create sub documents that store metadata to make the query easier to implement
    public int[] SeasonalPoints { get; set; }
}

class Program
{

    static void Main(string[] args)
    {
        //used v 2.4.3 of C# driver and v 3.4.1 of the db engine for this example
        var client = new MongoClient();
        IMongoDatabase db = client.GetDatabase("agg_example");

        var collectionName = "points";
        db.DropCollection(collectionName);

        IMongoCollection<BsonDocument> collection = db.GetCollection<BsonDocument>(collectionName);
        IEnumerable<BsonDocument> data = GetDummyData().Select(d=>d.ToBsonDocument());

        collection.InsertMany(data);

        //some seasons to filter by - note transformation to zero based
        var seasons = new[] {6, 7};

        //This is the query body:
        var seasonIndex = seasons.Select(i => i - 1);

        //This shall remove all un-necessary seasons from aggregation pipeline
        var bsonFilter = new BsonDocument { new BsonElement("Season", new BsonDocument("$in", new BsonArray(seasonIndex))) };

        var groupBy = new BsonDocument// think of this as a grouping with an anonyous object declaration
        {
             new BsonElement("_id", "$_id"),//This denotes the key by which to group - in this case the player's id
             new BsonElement("playerSum", new BsonDocument("$sum", "$SeasonalPoints")),//We aggregate the player's points after unwinding the array
             new BsonElement("player", new BsonDocument("$first", "$$CURRENT")),// preserve player reference for projection stage
        };

        var sort = Builders<BsonDocument>.Sort.Descending(doc => doc["playerSum"]);

        var unwindOptions = new AggregateUnwindOptions<BsonDocument>
        {
            IncludeArrayIndex = new StringFieldDefinition<BsonDocument>("Season")
        };

        var projection = Builders<BsonDocument>.Projection.Expression((doc => doc["player"]));

        List<BsonValue> sorted = collection
            .Aggregate()
            .Unwind(x=>x["SeasonalPoints"], unwindOptions)
            .Match(bsonFilter)
            .Group(groupBy)
            .Sort(sort)
            .Project(projection)
            .ToList();

    }

    private static IEnumerable<PlayerPoints> GetDummyData()
    {
        return new[]
        {
            new PlayerPoints
            {
                CreateDate = DateTime.Today,
                SeasonalPoints = Enumerable.Repeat(100,7).ToArray()
            },
            new PlayerPoints
            {
                CreateDate = DateTime.Today,
                SeasonalPoints = new []
                {
                    100,100,100,100,100,150,100
                }
            },
            new PlayerPoints
            {
                CreateDate = DateTime.Today,
                SeasonalPoints = new []
                {
                    100,100,100,100,100,0,300
                }
            },
        };
    }
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用MongoDB.Bson;
使用MongoDB.Bson.Serialization.Attributes;
使用MongoDB.Driver;
名称空间MongoAggregation
{
公开密封类播放点
{
公共对象Id{get;set;}
//请注意,mongo将所有内容都表示为UTC 0,因此如果存储本地时区值,请确保使用此属性
[BsonDateTimeOptions(种类=DateTimeKind.Local)]
公共日期时间CreateDate{get;set;}
公共整数点{get;set;}
//请注意,您的模型不允许球员不参加某个赛季,因此我冒昧地引入了一个新的子文档。
//最好创建存储元数据的子文档,以使查询更易于实现
公共int[]季节点{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//在本例中使用了C#driver的V2.4.3和db引擎的V3.4.1
var client=new MongoClient();
IMongoDatabase db=client.GetDatabase(“agg_示例”);
var collectionName=“点”;
db.DropCollection(collectionName);
IMongoCollection=db.GetCollection(collectionName);
IEnumerable data=GetDummyData()。选择(d=>d.ToBsonDocument());
集合。插入许多(数据);
//有些季节要按音符转换为零进行过滤
var seasons=新[]{6,7};
//这是查询主体:
var季节指数=季节。选择(i=>i-1);
//这将从聚合管道中移除所有不必要的季节
var bsonFilter=新的BsonDocument{new BsonElement(“季节”,新的BsonDocument(“$in”,新的BsonArray(季节指数)))};
var groupBy=new-BsonDocument//将其视为一个具有匿名对象声明的分组
{
new bsonement(“\u id”,“$\u id”),//这表示分组所依据的键-在本例中为播放器的id
new bsonement(“playerSum”,new BsonDocument($sum),“$seasionalpoints”),//我们在解开数组后聚合玩家的点数
新建BsonElement(“播放器”,新BsonDocument(“第一个“,“$$CURRENT”),//为投影阶段保留播放器参考
};
var sort=Builders.sort.Descending(doc=>doc[“playerSum]”);
var unwindOptions=新聚合unwindOptions
{
IncludeAryIndex=新的StringFieldDefinition(“季节”)
};
var projection=Builders.projection.Expression((doc=>doc[“player”]);
列表排序=集合
.Aggregate()
.展开(x=>x[“季节点”],展开选项)
.Match(b筛选)
.Group(groupBy)
.Sort(排序)
.项目(预测)
.ToList();
}
私有静态IEnumerable GetDummyData()
{
返回新的[]
{
新玩家点数
{
CreateDate=DateTime。今天,
季节点=可枚举。重复(100,7)。ToArray()
},
新玩家点数
{
CreateDate=DateTime。今天,
季节点数=新[]
{
100,100,100,100,100,150,100
}
},
新玩家点数
{
CreateDate=DateTime。今天,
季节点数=新[]
{
100,100,100,100,100,0,300
}
},
};
}
}
}

您可以使用
3.4
版本尝试以下聚合

聚合阶段-
$project
-
$sort
-
$project

数组聚合运算符-
$reduce
&
$slice

算术运算符-
$add

例如:

如果我查询第九季到第十季的排名,那么someId3是第一名,someId2是第一名 之后,someId1是最后一个

class Program {
    static void Main(string[] args) {

        IMongoClient client = new MongoClient();
        IMongoDatabase db = client.GetDatabase("db");
        IMongoCollection < PlayerPoints > collection = db.GetCollection < PlayerPoints > ("collection");

        var pipeline = collection.Aggregate()
            .Project(p => new {
                PlayerId = p.PlayerId, TotalPoints = p.SeasonalPoints.Skip(9).Take(2).Aggregate((s1, s2) => s1 + s2)
            })
            .SortByDescending(s => s.TotalPoints)
            .Project(e => new {
                e.PlayerId
            });

        var result = pipeline.ToListAsync();

    }
}
db.collection.aggregate([{
    "$project": {
        "PlayerId": "$_id",
        "TotalPoints": {
            "$reduce": {
                "input": {
                    "$slice": ["$SeasonalPoints", 9, 2]
                },
                "initialValue": 0,
                "in": {
                    "$add": ["$$value", "$$this"]
                }
            }
        },
        "_id": 0
    }
}, {
    "$sort": {
        "TotalPoints": -1
    }
}, {
    "$project": {
        "PlayerId": "$PlayerId",
        "_id": 0
    }
}])