Python 如何使用count all elements和Group by one request进行pymongo聚合
我有一个包含如下字段的集合:Python 如何使用count all elements和Group by one request进行pymongo聚合,python,mongodb,pymongo,Python,Mongodb,Pymongo,我有一个包含如下字段的集合: { "response": [ { "tag": "location", "tag_list": [ { "count": 31, "phrase": "philadelphia" }, {
{
"response": [
{
"tag": "location",
"tag_list": [
{
"count": 31,
"phrase": "philadelphia"
},
{
"count": 15,
"phrase": "usa"
}
]
},
{
"tag": "organization",
"tag_list": [ ... ]
},
{
"tag": "person",
"tag_list": [ ... ]
},
]
}
db.collection.aggregate([
{ "$addFields": {
"tags": { "$objectToArray": "$tags" }
}},
{ "$unwind": "$tags" },
{ "$unwind": "$tags.v" },
{ "$group": {
"_id": {
"tag": "$tags.k",
"phrase": "$tags.v.word"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.tag",
"tag_list": {
"$push": {
"count": "$count",
"phrase": "$_id.phrase"
}
}
}}
])
{
“_id”:“5cf54857bbc85fd0ff5640ba”,
“图书id”:“5cf172220fb516f706d00591”,
“标签”:{
“人”:[
{“开始匹配”:209,“长度匹配”:6,“单词”:“kimmel”}
],
“组织”:[
{“开始匹配”:107,“长度匹配”:12,“单词”:“费城”},
{“开始匹配”:209,“长度匹配”:13,“单词”:“kimmel中心”}
],
“地点”:[
{“开始匹配”:107,“长度匹配”:12,“单词”:“费城”}
]
},
“已删除”:false
}
我想收集分类中的不同单词并进行计数。
因此,输出应如下所示:
{
"response": [
{
"tag": "location",
"tag_list": [
{
"count": 31,
"phrase": "philadelphia"
},
{
"count": 15,
"phrase": "usa"
}
]
},
{
"tag": "organization",
"tag_list": [ ... ]
},
{
"tag": "person",
"tag_list": [ ... ]
},
]
}
db.collection.aggregate([
{ "$addFields": {
"tags": { "$objectToArray": "$tags" }
}},
{ "$unwind": "$tags" },
{ "$unwind": "$tags.v" },
{ "$group": {
"_id": {
"tag": "$tags.k",
"phrase": "$tags.v.word"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.tag",
"tag_list": {
"$push": {
"count": "$count",
"phrase": "$_id.phrase"
}
}
}}
])
这样的管道工作:
def管道功能(标记):
返回[
{'$replaceRoot':{'newRoot':'$tags'}},
{'$unwind':'${}'。格式(标记)},
{'$group':{''U id':'${}.word'。格式(标记),'count':{'$sum':1}},
{'$project':{'PHASE':'$\'id','count':1',\'id':0},
{$sort':{'count':-1}
]
但它会对每个标签发出请求。我想知道如何在一个请求中完成它。
感谢您的关注。如前所述,问题数据与当前声明的管道流程稍有不匹配,因为只能在数组上使用,并且问题中显示的标记不是数组
对于问题中提供的数据,您基本上需要这样的管道:
{
"response": [
{
"tag": "location",
"tag_list": [
{
"count": 31,
"phrase": "philadelphia"
},
{
"count": 15,
"phrase": "usa"
}
]
},
{
"tag": "organization",
"tag_list": [ ... ]
},
{
"tag": "person",
"tag_list": [ ... ]
},
]
}
db.collection.aggregate([
{ "$addFields": {
"tags": { "$objectToArray": "$tags" }
}},
{ "$unwind": "$tags" },
{ "$unwind": "$tags.v" },
{ "$group": {
"_id": {
"tag": "$tags.k",
"phrase": "$tags.v.word"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.tag",
"tag_list": {
"$push": {
"count": "$count",
"phrase": "$_id.phrase"
}
}
}}
])
同样,根据注释,由于标记
实际上是一个对象,因此您实际需要的是将其转换为一个项目数组,以便根据问题提出的子键收集数据
在您当前的管道中使用的似乎表明它在这里是合理使用的,因为它可以从MongoDB 3.4的后续补丁版本中获得,这是您现在应该在生产中使用的最低版本
这实际上与名字所说的差不多,并生成一个数组(或者更像python的“列表”)条目,这些条目被分解成键和值对。这些基本上是对象的“列表”(或“dict”条目),它们分别具有键k
和v
。第一个管道阶段的输出在提供的文档中如下所示:
{
"book_id": "5cf172220fb516f706d00591",
"tags": [
{
"k": "person",
"v": [
{
"start_match": 209,
"length_match": 6,
"word": "kimmel"
}
]
}, {
"k": "organization",
"v": [
{
"start_match": 107,
"length_match": 12,
"word": "philadelphia"
}, {
"start_match": 209,
"length_match": 13,
"word": "kimmel center"
}
]
}, {
"k": "location",
"v": [
{
"start_match": 107,
"length_match": 12,
"word": "philadelphia"
}
]
}
],
"deleted" : false
}
因此,您应该能够看到现在如何轻松访问这些k
值并在分组中使用它们,当然v
也是标准数组。所以它只是两个阶段,如图所示,然后是两个阶段。第一个用于通过组合键进行收集,第二个用于根据主分组键进行收集,同时将其他累积添加到该条目内的“列表”中
当然,上面清单的输出并不完全是您在问题中所要求的,但是数据基本上是存在的。您可以选择添加一个或阶段,将\u id
键重命名为最终聚合阶段:
{ "$addFields": {
"_id": "$$REMOVE",
"tag": "$_id"
}}
或者简单地做一些pythonic操作,在光标输出上进行一些列表理解:
cursor = db.collection.aggregate([
{ "$addFields": {
"tags": { "$objectToArray": "$tags" }
}},
{ "$unwind": "$tags" },
{ "$unwind": "$tags.v" },
{ "$group": {
"_id": {
"tag": "$tags.k",
"phrase": "$tags.v.word"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.tag",
"tag_list": {
"$push": {
"count": "$count",
"phrase": "$_id.phrase"
}
}
}}
])
output = [{ 'tag': doc['_id'], 'tag_list': doc['tag_list'] } for doc in cursor]
print({ 'response': output });
最终输出为“列表”,可用于响应
:
{
"tag_list": [
{
"count": 1,
"phrase": "philadelphia"
}
],
"tag": "location"
},
{
"tag_list": [
{
"count": 1,
"phrase": "kimmel"
}
],
"tag": "person"
},
{
"tag_list": [
{
"count": 1,
"phrase": "kimmel center"
}, {
"count": 1,
"phrase": "philadelphia"
}
],
"tag": "organization"
}
注意,使用列表理解方法,您可以更好地控制作为输出的“键”的顺序,因为MongoDB本身只需在投影中添加新的键名,使现有键保持优先顺序。如果这类事情对你很重要,那就是。尽管它确实不应该是这样,因为所有对象/Dict类结构都不应该被认为具有任何设置的键顺序。这就是数组(或列表)的用途 “像这样的管道工作…”-实际上它不能像现在这样显示,因为在问题中,标记
显示为对象{}
,而不是数组[]
。因此,{$unwind:“$tags”}
将抛出一个错误($unwind
仅适用于实际数组)。我建议您的实际数据的结构稍有不同,或者您声称的管道尝试实际上不起作用。您需要清楚地指定这两个选项中哪一个是正确的。在这里对您的问题进行编辑是合适的。这很奇怪,但是当我删除{$unwind:“$tags”}
时,输出不会改变。也许这是因为清单在里面。但你是对的<代码>{$unwind:“$tags”}
是不必要的。我把它从我的请求中删除,但我的回答仍然是真实的。所有的工作。这是一个绝妙的回答。没什么可补充的。谢谢你的快速回复+1.