我有一些市场提要数据,我正尝试在 Ubuntu 16.04 上使用 mongodb 3.4.5 在给定的日期范围内生成一个很好的摘要。
这是一个示例文档。每个文档可能包含多个批量数据,包括买入、卖出和填写。
{
"MarketName" : "BIX",
"Nounce" : 12040,
"Buys" : [
{
"Type" : 2,
"Rate" : 0.08068147,
"Quantity" : 55.57280163
},
{
"Type" : 1,
"Rate" : 0.07980372,
"Quantity" : 0
},
{
"Type" : 0,
"Rate" : 0.07962334,
"Quantity" : 34.96018931
},
{
"Type" : 1,
"Rate" : 0.07960592,
"Quantity" : 0
}
],
"Sells" : [
{
"Type" : 0,
"Rate" : 0.08070098,
"Quantity" : 4.08189692
},
{
"Type" : 0,
"Rate" : 0.08112318,
"Quantity" : 10
},
{
"Type" : 1,
"Rate" : 0.08112319,
"Quantity" : 0
},
{
"Type" : 1,
"Rate" : 0.08149567,
"Quantity" : 0
}
],
"Fills" : [
{
"OrderType" : "SELL",
"Rate" : 0.08068147,
"Quantity" : 0.51627134,
"TimeStamp" : "2017-07-25T15:20:34.357"
},
{
"OrderType" : "BUY",
"Rate" : 0.08048147,
"Quantity" : 0.51007134,
"TimeStamp" : "2017-07-25T15:20:34.357"
}
],
"TimeStamp" : ISODate("2017-07-26T22:32:20.741+08:00")
}
我一直在尝试各种放松和小组、项目和推送等。但我离我想要的输出还差得很远。因为类型是对象键名,所以我很难找到要分组的东西。
我正在寻找的输出是这样的。
{
"MarketName" : "RRG",
"Buys" : {
totalCount: 99, //size/count of all items in Buys array
avgRate: 0.07980372, //avg rate of all buy object items
totalQuantity: 3.09239812, //sum of all buy array items, quantity values
totalValue: 306.14741388, //avgRate * totalQuantity
type0: {
totalCount: 19, //count of items in Buy array oftype 0
avgRate: 0.07980372, //avg rate of all buy object items of type 0
totalQuantity: 3.09239812, //sum of all buy object quantity values oftype 0
totalValue: 30.14741388, //avgRate * totalQuantity
},
type1: {
totalCount: 9,
avgRate: 0.07980372,
totalQuantity: 3.09239812,
totalValue: 30.14741388,
},
type2: {
totalCount: 12,
avgRate: 0.07980372,
totalQuantity: 3.09239812,
totalValue: 30.14741388,
}
},
"Sells" : {
..same as buys format
},
"Fills" : {
..same as buys format
}
}
如果有人能以任何方式帮助我,我将不胜感激。
这是我设法开始工作的查询,但距离我想要的还有很长的路要走,而且我不是 mongo 专家,所以很难知道如何继续。
db.getCollection('tinfo').aggregate(
[
{
$match: {
'$and': [
{'Type': {$eq: 'market'}},
{'TimeStamp': {$lte: new Date()}},
{'TimeStamp': {$gte: new Date(Date.now() - 24 * 60 * 60 * 1000)}},
{'MarketName': {$eq: 'BIX'}}
]
}
},
},
{ $unwind: "$Buys" },
{ $unwind: "$Sells" },
{ $unwind: "$Fills" },
{
$group: {
_id: {_id: "$_id", type: "$Buys.Type"},
count: {$sum: 1},
avgRate: {$avg: "$Buys.Rate"},
quantity: {$sum: "$Buys.Quantity"}
}
},{
$project: {
type: "$_id.type",
count: 1,
avgRate: 1,
quantity: 1,
total: {$multiply: ["$quantity", "$avgRate"]}
}
},{
$group: {
"_id": {
"_id" : "$_id._id"
},
"results" : {
$push: {
"k": "$type",
"v": {
"count": "$count",
"avgRate": "$avgRate",
"quantity": "$quantity"
}
}
}
}
}
])
最佳答案
这当然是可能的,请注意,我实际上是在“仅在最后阶段”故意使用实际的 MongoDB 3.4 功能,这通常强调您并不真正需要它们,因为无需“命名键”在输出中。
一般的 list 是这样的:
var endDate = new Date(),
startDate = new Date(endDate.valueOf() - 24 * 60 * 60 * 60 * 1000 );
db.getCollection('tinfo').aggregate([
/*
{ "$match": {
"TimeStamp": {
"$gte": startDate, "$lt": endDate
}
}},
*/
{ "$project": {
"MarketName": 1,
"combined": {
"$concatArrays": [
{ "$map": {
"input": "$Buys",
"as": "b",
"in": {
"ttype": "Buys",
"Type": "$$b.Type",
"Rate": "$$b.Rate",
"Quantity": "$$b.Quantity"
}
}},
{ "$map": {
"input": "$Sells",
"as": "s",
"in": {
"ttype": "Sells",
"Type": "$$s.Type",
"Rate": "$$s.Rate",
"Quantity": "$$s.Quantity"
}
}},
{ "$map": {
"input": "$Fills",
"as": "f",
"in": {
"ttype": "Fills",
"Type": "$$f.OrderType",
"Rate": "$$f.Rate",
"Quantity": "$$f.Quantity"
}
}}
]
}
}},
{ "$unwind": "$combined" },
{ "$group": {
"_id": {
"MarketName": "$MarketName",
"ttype": "$combined.ttype",
"Type": "$combined.Type"
},
"totalCount": { "$sum": 1 },
"avgRate": { "$avg": "$combined.Rate" },
"totalQuantity": { "$sum": "$combined.Quantity" },
}},
{ "$group": {
"_id": {
"MarketName": "$_id.MarketName",
"ttype": "$_id.ttype",
},
"Types": {
"$push": {
"k": {
"$concat": [
"type",
{ "$cond": {
"if": { "$eq": [ "$_id.ttype", "Fills" ] },
"then": "$_id.Type",
"else": { "$substr": ["$_id.Type",0,1] }
}}
]
},
"v": {
"totalCount": "$totalCount",
"avgRate": "$avgRate",
"totalQuantity": "$totalQuantity",
"totalValue": { "$multiply": [ "$totalQuantity", "$avgRate" ] }
}
}
},
"totalCount": { "$sum": "$totalCount" },
"avgRate": { "$avg": "$avgRate" },
"totalQuantity": { "$sum": "$totalQuantity" }
}},
{ "$group": {
"_id": "$_id.MarketName",
"data": {
"$push": {
"k": "$_id.ttype",
"v": {
"totalCount": "$totalCount",
"avgRate": "$avgRate",
"totalQuantity": "$totalQuantity",
"totalValue": { "$multiply": [ "$totalQuantity", "$avgRate" ] },
"Types": "$Types"
}
}
}
}},
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
[{ "k": "MarketName", "v": "$_id" }],
{ "$map": {
"input": "$data",
"as": "d",
"in": {
"k": "$$d.k",
"v": {
"$arrayToObject": {
"$concatArrays": [
[
{ "k": "totalCount", "v": "$$d.v.totalCount" },
{ "k": "avgRate", "v": "$$d.v.avgRate" },
{ "k": "totalQuantity", "v": "$$d.v.totalQuantity" },
{ "k": "totalValue", "v": "$$d.v.totalValue" }
],
"$$d.v.Types"
]
}
}
}
}}
]
}
}
}}
])
其中的大纲是。
投影一个组合数组,这是避免“笛卡尔积”所必需的,否则如果您使用 $unwind 会发生这种情况分别在每个阵列上。所以你想把所有的数组合并成一个格式一致的数组,以便以后处理。这就是我们使用 $concatArrays 所做的和 $map做一点“ reshape ”并确定哪个“ttype”,以便我们知道“源”数组。
逐渐分组 由于“总数”出现在不同的级别,我们首先要 $group在“inner”“type” 属性上,然后逐渐向外工作,直到回到顶层。在每个阶段,您都会进行其他计算,例如 $multiply在 $sum 上和 $avg结果。
Finally Reshape 当在聚合框架中使用时,这基本上都是关于 $arrayToObject 的。在这里,我们只是以数组格式提供所有内容作为“键”和“值”对(还解释了早期阶段使用的 “k” 和 “v”),以便该运算符可以“转换”为具有“命名键”的对象格式。
当然,最后阶段也可以在客户端代码中完成,但由于版本受支持,我包含了实际的管道阶段来完成它。
然后输出是:
{
"MarketName" : "BIX",
"Buys" : {
"totalCount" : 4.0,
"avgRate" : 0.08000321,
"totalQuantity" : 90.53299094,
"totalValue" : 7.24292988610092,
"type2" : {
"totalCount" : 1.0,
"avgRate" : 0.08068147,
"totalQuantity" : 55.57280163,
"totalValue" : 4.4836953275268
},
"type1" : {
"totalCount" : 2.0,
"avgRate" : 0.07970482,
"totalQuantity" : 0.0,
"totalValue" : 0.0
},
"type0" : {
"totalCount" : 1.0,
"avgRate" : 0.07962334,
"totalQuantity" : 34.96018931,
"totalValue" : 2.7836470398945
}
},
"Sells" : {
"totalCount" : 4.0,
"avgRate" : 0.081110755,
"totalQuantity" : 14.08189692,
"totalValue" : 1.14219329101337,
"type1" : {
"totalCount" : 2.0,
"avgRate" : 0.08130943,
"totalQuantity" : 0.0,
"totalValue" : 0.0
},
"type0" : {
"totalCount" : 2.0,
"avgRate" : 0.08091208,
"totalQuantity" : 14.08189692,
"totalValue" : 1.13939557014279
}
},
"Fills" : {
"totalCount" : 2.0,
"avgRate" : 0.08058147,
"totalQuantity" : 1.02634268,
"totalValue" : 0.0827042018781396,
"typeBUY" : {
"totalCount" : 1.0,
"avgRate" : 0.08048147,
"totalQuantity" : 0.51007134,
"totalValue" : 0.0410512912480698
},
"typeSELL" : {
"totalCount" : 1.0,
"avgRate" : 0.08068147,
"totalQuantity" : 0.51627134,
"totalValue" : 0.0416535306300698
}
}
}
当然是基于所提供的数据。实际的“计算”在实现中可能会有所不同(我只是遵循您自己的笔记),但这是要遵循的一般结构。
如前所述,此处的输出格式确实不需要 $replaceRoot 的新功能和 $arrayToObject 以获得最终结果。所有被转换的是光标上的最终文档响应。
因此,如果您查看 $replaceRoot 之前的输出阶段被调用你看到:
{
"_id" : "BIX",
"data" : [
{
"k" : "Buys",
"v" : {
"totalCount" : 4.0,
"avgRate" : 0.08000321,
"totalQuantity" : 90.53299094,
"totalValue" : 7.24292988610092,
"Types" : [
{
"k" : "type2",
"v" : {
"totalCount" : 1.0,
"avgRate" : 0.08068147,
"totalQuantity" : 55.57280163,
"totalValue" : 4.4836953275268
}
},
{
"k" : "type1",
"v" : {
"totalCount" : 2.0,
"avgRate" : 0.07970482,
"totalQuantity" : 0.0,
"totalValue" : 0.0
}
},
{
"k" : "type0",
"v" : {
"totalCount" : 1.0,
"avgRate" : 0.07962334,
"totalQuantity" : 34.96018931,
"totalValue" : 2.7836470398945
}
}
]
}
},
{
"k" : "Sells",
"v" : {
"totalCount" : 4.0,
"avgRate" : 0.081110755,
"totalQuantity" : 14.08189692,
"totalValue" : 1.14219329101337,
"Types" : [
{
"k" : "type1",
"v" : {
"totalCount" : 2.0,
"avgRate" : 0.08130943,
"totalQuantity" : 0.0,
"totalValue" : 0.0
}
},
{
"k" : "type0",
"v" : {
"totalCount" : 2.0,
"avgRate" : 0.08091208,
"totalQuantity" : 14.08189692,
"totalValue" : 1.13939557014279
}
}
]
}
},
{
"k" : "Fills",
"v" : {
"totalCount" : 2.0,
"avgRate" : 0.08058147,
"totalQuantity" : 1.02634268,
"totalValue" : 0.0827042018781396,
"Types" : [
{
"k" : "typeBUY",
"v" : {
"totalCount" : 1.0,
"avgRate" : 0.08048147,
"totalQuantity" : 0.51007134,
"totalValue" : 0.0410512912480698
}
},
{
"k" : "typeSELL",
"v" : {
"totalCount" : 1.0,
"avgRate" : 0.08068147,
"totalQuantity" : 0.51627134,
"totalValue" : 0.0416535306300698
}
}
]
}
}
]
}
当使用 .map() 处理游标时,我们可以轻松地在客户端代码中执行相同的转换。和 .reduce() JavaScript 函数作为 shell 示例:
var endDate = new Date(),
startDate = new Date(endDate.valueOf() - 24 * 60 * 60 * 60 * 1000 );
db.getCollection('tinfo').aggregate([
/*
{ "$match": {
"TimeStamp": {
"$gte": startDate, "$lt": endDate
}
}},
*/
{ "$project": {
"MarketName": 1,
"combined": {
"$concatArrays": [
{ "$map": {
"input": "$Buys",
"as": "b",
"in": {
"ttype": "Buys",
"Type": "$$b.Type",
"Rate": "$$b.Rate",
"Quantity": "$$b.Quantity"
}
}},
{ "$map": {
"input": "$Sells",
"as": "s",
"in": {
"ttype": "Sells",
"Type": "$$s.Type",
"Rate": "$$s.Rate",
"Quantity": "$$s.Quantity"
}
}},
{ "$map": {
"input": "$Fills",
"as": "f",
"in": {
"ttype": "Fills",
"Type": "$$f.OrderType",
"Rate": "$$f.Rate",
"Quantity": "$$f.Quantity"
}
}}
]
}
}},
{ "$unwind": "$combined" },
{ "$group": {
"_id": {
"MarketName": "$MarketName",
"ttype": "$combined.ttype",
"Type": "$combined.Type"
},
"totalCount": { "$sum": 1 },
"avgRate": { "$avg": "$combined.Rate" },
"totalQuantity": { "$sum": "$combined.Quantity" },
}},
{ "$group": {
"_id": {
"MarketName": "$_id.MarketName",
"ttype": "$_id.ttype",
},
"Types": {
"$push": {
"k": {
"$concat": [
"type",
{ "$cond": {
"if": { "$eq": [ "$_id.ttype", "Fills" ] },
"then": "$_id.Type",
"else": { "$substr": ["$_id.Type",0,1] }
}}
]
},
"v": {
"totalCount": "$totalCount",
"avgRate": "$avgRate",
"totalQuantity": "$totalQuantity",
"totalValue": { "$multiply": [ "$totalQuantity", "$avgRate" ] }
}
}
},
"totalCount": { "$sum": "$totalCount" },
"avgRate": { "$avg": "$avgRate" },
"totalQuantity": { "$sum": "$totalQuantity" }
}},
{ "$group": {
"_id": "$_id.MarketName",
"data": {
"$push": {
"k": "$_id.ttype",
"v": {
"totalCount": "$totalCount",
"avgRate": "$avgRate",
"totalQuantity": "$totalQuantity",
"totalValue": { "$multiply": [ "$totalQuantity", "$avgRate" ] },
"Types": "$Types"
}
}
}
}},
/*
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
[{ "k": "MarketName", "v": "$_id" }],
{ "$map": {
"input": "$data",
"as": "d",
"in": {
"k": "$$d.k",
"v": {
"$arrayToObject": {
"$concatArrays": [
[
{ "k": "totalCount", "v": "$$d.v.totalCount" },
{ "k": "avgRate", "v": "$$d.v.avgRate" },
{ "k": "totalQuantity", "v": "$$d.v.totalQuantity" },
{ "k": "totalValue", "v": "$$d.v.totalValue" }
],
"$$d.v.Types"
]
}
}
}
}}
]
}
}
}}
*/
])
.map( doc => Object.assign(
{ "MarketName": doc._id },
doc.data.map( d => ({
"k": d.k,
"v": Object.assign(
Object.keys(d.v)
.filter(k => k !== 'Types')
.map( k => ({ [k]: d.v[k] }))
.reduce((acc,curr) => Object.assign(acc,curr),{}),
d.v.Types.reduce((acc,curr) => Object.assign(acc,{ [curr.k]: curr.v }),{})
)
}))
.reduce((acc,curr) => Object.assign(acc,{ [curr.k]: curr.v }),{})
))
这当然会产生完全相同的输出:
{
"MarketName" : "BIX",
"Buys" : {
"totalCount" : 4.0,
"avgRate" : 0.08000321,
"totalQuantity" : 90.53299094,
"totalValue" : 7.24292988610092,
"type2" : {
"totalCount" : 1.0,
"avgRate" : 0.08068147,
"totalQuantity" : 55.57280163,
"totalValue" : 4.4836953275268
},
"type1" : {
"totalCount" : 2.0,
"avgRate" : 0.07970482,
"totalQuantity" : 0.0,
"totalValue" : 0.0
},
"type0" : {
"totalCount" : 1.0,
"avgRate" : 0.07962334,
"totalQuantity" : 34.96018931,
"totalValue" : 2.7836470398945
}
},
"Sells" : {
"totalCount" : 4.0,
"avgRate" : 0.081110755,
"totalQuantity" : 14.08189692,
"totalValue" : 1.14219329101337,
"type1" : {
"totalCount" : 2.0,
"avgRate" : 0.08130943,
"totalQuantity" : 0.0,
"totalValue" : 0.0
},
"type0" : {
"totalCount" : 2.0,
"avgRate" : 0.08091208,
"totalQuantity" : 14.08189692,
"totalValue" : 1.13939557014279
}
},
"Fills" : {
"totalCount" : 2.0,
"avgRate" : 0.08058147,
"totalQuantity" : 1.02634268,
"totalValue" : 0.0827042018781396,
"typeBUY" : {
"totalCount" : 1.0,
"avgRate" : 0.08048147,
"totalQuantity" : 0.51007134,
"totalValue" : 0.0410512912480698
},
"typeSELL" : {
"totalCount" : 1.0,
"avgRate" : 0.08068147,
"totalQuantity" : 0.51627134,
"totalValue" : 0.0416535306300698
}
}
}
关于javascript - 聚合多个数组的总数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45341584/
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat