问题描述
我有以下收藏
{"_id" : ObjectId("5b18d14cbc83fd271b6a157c"),状态":待定","description": "你必须完成挑战...",}{"_id" : ObjectId("5b18d31a27a37696ec8b5773"),状态":已完成","描述": "完成...",}{"_id" : ObjectId("5b18d31a27a37696ec8b5775"),状态":待定","描述": "待定...",}{"_id" : ObjectId("5b18d31a27a37696ec8b5776"),状态":进行中","描述": "进行中...",}
我需要按 status
分组并动态获取 status
我不认为这是一个好主意,主要是因为我在这里根本看不到任何聚合"是在分组"之后添加到数组你同样 $push
所有该内容通过 "status"
分组键转换为数组,然后转换为 $replaceRoot
和 $arrayToObject
:
db.collection.aggregate([{$组":{"_id": "$status",数据":{$push":$$ROOT"}}},{$组":{_id":空,数据": {$push":{"k": "$_id",v":$数据"}}}},{$replaceRoot":{"newRoot": { "$arrayToObject": "$data" }}}])
返回:
{进行中" : [{"_id" : ObjectId("5b18d31a27a37696ec8b5776"),状态":进行中",描述":进行中……"}],完全的" : [{"_id" : ObjectId("5b18d31a27a37696ec8b5773"),状态":已完成",描述":完成……"}],待办的" : [{"_id" : ObjectId("5b18d14cbc83fd271b6a157c"),状态":待定","description": "你必须完成挑战……"},{"_id" : ObjectId("5b18d31a27a37696ec8b5775"),状态":待定",描述":待定……"}]}
那可能没问题如果您实际上事先聚合"过,但是在任何实际大小的集合上所做的一切都是试图将整个集合强制转换为单个文档,这可能会破坏 16MB 的 BSON 限制,所以我什至不建议尝试这个在这一步之前没有分组"其他东西.
坦率地说,以下相同的代码做同样的事情,并且没有聚合技巧和 BSON 限制问题:
var obj = {};//使用 forEach 作为表示任何"游标迭代形式的前提db.collection.find().forEach(d => {如果(!obj.hasOwnProperty(d.status))obj[d.status] = [];obj[d.status].push(d);})打印json(对象);
或者更短一点:
var obj = {};//使用 forEach 作为表示任何"游标迭代形式的前提db.collection.find().forEach(d =>obj[d.status] = [...(obj.hasOwnProperty(d.status)) ?对象[d.status] : [],d])打印json(对象);
聚合用于数据缩减",任何只是重塑结果"而不实际减少从服务器返回的数据的东西通常都可以在客户端代码中更好地处理.无论您做什么,您仍然会返回所有数据,并且客户端处理游标的开销要小得多.并且没有任何限制.
I have following collection
{
"_id" : ObjectId("5b18d14cbc83fd271b6a157c"),
"status" : "pending",
"description" : "You have to complete the challenge...",
}
{
"_id" : ObjectId("5b18d31a27a37696ec8b5773"),
"status" : "completed",
"description" : "completed...",
}
{
"_id" : ObjectId("5b18d31a27a37696ec8b5775"),
"status" : "pending",
"description" : "pending...",
}
{
"_id" : ObjectId("5b18d31a27a37696ec8b5776"),
"status" : "inProgress",
"description" : "inProgress...",
}
I need to group by status
and get all the keys dynamically which are in status
[
{
"completed": [
{
"_id": "5b18d31a27a37696ec8b5773",
"status": "completed",
"description": "completed..."
}
]
},
{
"pending": [
{
"_id": "5b18d14cbc83fd271b6a157c",
"status": "pending",
"description": "You have to complete the challenge..."
},
{
"_id": "5b18d31a27a37696ec8b5775",
"status": "pending",
"description": "pending..."
}
]
},
{
"inProgress": [
{
"_id": "5b18d31a27a37696ec8b5776",
"status": "inProgress",
"description": "inProgress..."
}
]
}
]
Not that I think it's a good idea and mostly because I don't see any "aggregation" here at all is that after "grouping" to add to an array you similarly $push
all that content into array by the "status"
grouping key and then convert into keys of a document in a $replaceRoot
with $arrayToObject
:
db.collection.aggregate([
{ "$group": {
"_id": "$status",
"data": { "$push": "$$ROOT" }
}},
{ "$group": {
"_id": null,
"data": {
"$push": {
"k": "$_id",
"v": "$data"
}
}
}},
{ "$replaceRoot": {
"newRoot": { "$arrayToObject": "$data" }
}}
])
Returns:
{
"inProgress" : [
{
"_id" : ObjectId("5b18d31a27a37696ec8b5776"),
"status" : "inProgress",
"description" : "inProgress..."
}
],
"completed" : [
{
"_id" : ObjectId("5b18d31a27a37696ec8b5773"),
"status" : "completed",
"description" : "completed..."
}
],
"pending" : [
{
"_id" : ObjectId("5b18d14cbc83fd271b6a157c"),
"status" : "pending",
"description" : "You have to complete the challenge..."
},
{
"_id" : ObjectId("5b18d31a27a37696ec8b5775"),
"status" : "pending",
"description" : "pending..."
}
]
}
That might be okay IF you actually "aggregated" beforehand, but on any practically sized collection all that is doing is trying force the whole collection into a single document, and that's likely to break the BSON Limit of 16MB, so I just would not recommend even attempting this without "grouping" something else before this step.
Frankly, the same following code does the same thing, and without aggregation tricks and no BSON limit problem:
var obj = {};
// Using forEach as a premise for representing "any" cursor iteration form
db.collection.find().forEach(d => {
if (!obj.hasOwnProperty(d.status))
obj[d.status] = [];
obj[d.status].push(d);
})
printjson(obj);
Or a bit shorter:
var obj = {};
// Using forEach as a premise for representing "any" cursor iteration form
db.collection.find().forEach(d =>
obj[d.status] = [
...(obj.hasOwnProperty(d.status)) ? obj[d.status] : [],
d
]
)
printjson(obj);
Aggregations are used for "data reduction" and anything that is simply "reshaping results" without actually reducing the data returned from the server is usually better handled in client code anyway. You're still returning all data no matter what you do, and the client processing of the cursor has considerably less overhead. And NO restrictions.
这篇关于$group by 后的动态键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!