我有一些像这样的交易数据
{
"_id" : 1498290900.0,
"trade" : {
"type" : "Modify",
"data" : {
"type" : "bid",
"rate" : "0.00658714",
"amount" : "3.82354427"
},
"date" : 1498290930291.0,
"name" : "TLX"
}
},{
"_id" : 1498290900.0,
"trade" : {
"type" : "Modify",
"data" : {
"type" : "ask",
"rate" : "0.00658714",
"amount" : "3.82354427"
},
"date" : 1498290930291.0,
"name" : "TLX"
}
},{
"_id" : 1498290900.0,
"trade" : {
"type" : "Remove",
"data" : {
"type" : "ask",
"rate" : "0.00680891"
},
"date" : 1498290931349.0,
"name" : "TLX"
}
}
这些来自$rewind
,因此_id
相同。我希望下一步做的是将它们分组在_id
上,所以我试试
{
$group: {
_id: {_id: "$_id", name: "$trade.type",dtype: "$trade.data.type"},
count : {$sum: 1}
},
},{$project: { _id: "$_id._id", type: "$_id.name", count: 1, dtype: "$_id.dtype" } },
{
$group: {
_id: "$_id",
results: { $push : "$$ROOT" }
}
}
哪个很好,请给我以下
{
"_id" : 1498276800.0,
"results" : [
{
"count" : 16.0,
"_id" : 1498276800.0,
"type" : "Modify",
"dtype" : "bid"
},
{
"count" : 15.0,
"_id" : 1498276800.0,
"type" : "Remove",
"dtype" : "bid"
},
{
"count" : 3.0,
"_id" : 1498276800.0,
"type" : "Remove",
"dtype" : "ask"
},
{
"count" : 1.0,
"_id" : 1498276800.0,
"type" : "Modify",
"dtype" : "ask"
}
]
}
但我试图让输出更像这样
{
"_id" : 1498276800.0,
"Modify": {
"bid":{
"count": 16.0
},
"ask": {
"count": 1.0
}
},
"Remove": {
"bid":{
"count": 15.0
},
"ask": {
"count": 3.0
}
}
}
但$projections
没有多少玩法让我接近。
有人能指出我正确的方向吗?
感谢。
更新
排除上一个管道阶段,这是一个示例文档,每个类型的出价/询问很好,可以按_id分组。
{
"_id" : {
"_id" : 1498276800.0,
"type" : "orderBookRemove"
},
"results" : [
{
"k" : "bid",
"v" : {
"count" : 15.0
}
},
{
"k" : "ask",
"v" : {
"count" : 3.0
}
}
]
},
{
"_id" : {
"_id" : 1498276800.0,
"type" : "orderBookModify"
},
"results" : [
{
"k" : "bid",
"v" : {
"count" : 16.0
}
},
{
"k" : "ask",
"v" : {
"count" : 1.0
}
}
]
}
当应用最后一部分管道时,即
{ "$group": {
"_id": "$_id._id",
"results": {
"$push": {
"k": "$_id.type",
"v": "$results"
}
}
}}
我得到了这个,只有第一个出价'结果数组的元素。第二项'问'擅离职守?
{
"_id" : 1498280700.0,
"results" : [
{
"k" : "orderBookRemove",
"v" : [
{
"k" : "bid",
"v" : {
"count" : 9.0
}
}
]
},
{
"k" : "orderBookModify",
"v" : [
{
"k" : "bid",
"v" : {
"count" : 6.0
}
}
]
}
]
}
答案 0 :(得分:1)
这完全取决于你可用的MongoDB版本,或者不是真的,具体取决于你如何看待它。正如你所说的那样,数据实际上来自一个数组,因此我将以该格式开始,并从那里处理每个选项。
正在考虑的来源是:
{
"_id" : ObjectId("594f3a530320738061df3eea"),
"data" : [
{
"_id" : 1498290900,
"trade" : {
"type" : "Modify",
"data" : {
"type" : "bid",
"rate" : "0.00658714",
"amount" : "3.82354427"
},
"date" : 1498290930291,
"name" : "TLX"
}
},
{
"_id" : 1498290900,
"trade" : {
"type" : "Modify",
"data" : {
"type" : "ask",
"rate" : "0.00658714",
"amount" : "3.82354427"
},
"date" : 1498290930291,
"name" : "TLX"
}
},
{
"_id" : 1498290900,
"trade" : {
"type" : "Remove",
"data" : {
"type" : "ask",
"rate" : "0.00680891"
},
"date" : 1498290931349,
"name" : "TLX"
}
}
]
}
只需谨慎使用$replaceRoot
和$arrayToObject
:
db.dtest.aggregate([
{ "$unwind": "$data" },
{ "$group": {
"_id": {
"_id": "$data._id",
"type": "$data.trade.type",
"dtype": "$data.trade.data.type"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": {
"_id": "$_id._id",
"type": "$_id.type"
},
"results": {
"$push": {
"k": "$_id.dtype",
"v": {
"count": "$count"
}
}
}
}},
{ "$group": {
"_id": "$_id._id",
"results": {
"$push": {
"k": "$_id.type",
"v": "$results"
}
}
}},
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
[{ "k": "_id", "v": "$_id" }],
{ "$map": {
"input": "$results",
"as": "r",
"in": {
"k": "$$r.k",
"v": { "$arrayToObject": "$$r.v" }
}
}}
]
}
}
}}
])
在大多数情况下,我们只需执行聚合数组表单并在客户端进行转换,这可能是最有意义的。由于该部分已经完成,我们并不需要额外的聚合,因此我们不再需要进一步减少数据。
在大多数语言中都很简单,但作为在shell中运行的基本JavaScript概念:
db.dtest.aggregate([
{ "$unwind": "$data" },
{ "$group": {
"_id": {
"_id": "$data._id",
"type": "$data.trade.type",
"dtype": "$data.trade.data.type"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": {
"_id": "$_id._id",
"type": "$_id.type"
},
"results": {
"$push": {
"k": "$_id.dtype",
"v": {
"count": "$count"
}
}
}
}},
{ "$group": {
"_id": "$_id._id",
"results": {
"$push": {
"k": "$_id.type",
"v": "$results"
}
}
}}
]).map(doc =>
doc.results.map(r =>
({ k: r.k, v: r.v.reduce((acc,curr) =>
Object.assign(acc, { [curr.k]: curr.v }),{})
})
).reduce((acc,curr) =>
Object.assign(acc, { [curr.k]: curr.v }),{ _id: doc._id })
)
在处理游标时,基本上做同样的事情就像新的花哨管道阶段正在为每个文档做的那样。
所以它真的只是表明除非你打算进一步聚合结果,甚至不是从这个结果聚合,否则根本没有必要使用花哨的新运算符。同样的事情是在相当少的代码行中实现的,而且表达的简洁性要小得多。
两者输出相同的东西:
{
"_id" : 1498290900,
"Modify" : {
"ask" : {
"count" : 1
},
"bid" : {
"count" : 1
}
},
"Remove" : {
"ask" : {
"count" : 1
}
}
}
从您的更新中获取数据我应用:
db.test.aggregate([
{ "$group": {
"_id": "$_id._id",
"results": {
"$push": {
"k": "$_id.type",
"v": "$results"
}
}
}},
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
[{ "k": "_id", "v": "$_id" }],
{ "$map": {
"input": "$results",
"as": "r",
"in": {
"k": "$$r.k",
"v": { "$arrayToObject": "$$r.v" }
}
}}
]
}
}
}}
])
获得预期的输出:
{
"_id" : 1498276800.0,
"orderBookRemove" : {
"bid" : {
"count" : 15.0
},
"ask" : {
"count" : 3.0
}
},
"orderBookModify" : {
"bid" : {
"count" : 16.0
},
"ask" : {
"count" : 1.0
}
}
}
因此,您声明的输出为false,并且您没有关注该示例。