如何在 pymongo 中将聚合操作的结果写为另一个集合中的一个文档

Posted

技术标签:

【中文标题】如何在 pymongo 中将聚合操作的结果写为另一个集合中的一个文档【英文标题】:How can I write results of aggregation operation in pymongo as one document in another collection 【发布时间】:2019-09-01 04:39:41 【问题描述】:

好吧,我想创建某种 MapReduce 算法来为文本文档创建反向索引。 在映射部分,我做了这样的事情

letters = ['a']
regx = re.compile("^("+"|".join(letters)+')')
selectedWords = directIndex.aggregate([
     "$match":  "words.word": regx  ,
     "$unwind": "$words" ,
     "$match":  "words.word": regx  ,
     "$group":  "_id":  "word":"$words.word", "count":"$words.count", 'document' : '$document'   ])

好吧,在这里,我按首字母选择所有与之相关的单词和信息。在此之后,我将此信息写入另一个集合:

myinvcol.insert_one('letter':str(''.join(letters)),'words':selectedWords )

在下一步中,我正在读取每个插入的文档并执行缩减操作 dict('wordName':documents:[document1:count1, document2:count2, etc], 'wordName2:documents:[...] ') 并对这个字典做一些额外的操作

现在,有趣的部分)): 是否可以在 MongoDB 服务器上完全执行第一步(地图部分),也就是聚合?换句话说,我知道有 '$out' 运算符:

letters = ['a']
regx = re.compile("^("+"|".join(letters)+')')
selectedWords = directIndex.aggregate([
     "$match":  "words.word": regx  ,
     "$unwind": "$words" ,
     "$match":  "words.word": regx  ,
     "$group":  "_id":  "word":"$words.word", "count":"$words.count", 'document' : '$document'   
     "$out" : 'InverseIndex'])

它允许我将聚合结果写入另一个集合,但它不能做我想要的:而不是插入一个文档:

'letter':str(''.join(letters)),'words':selectedWords , 

我有很多插入

 "_id":  "word":"$words.word", "count":"$words.count", 'document' : '$document'  . 

那么,最后,有没有一种方法可以在聚合中创建一个文档,在 $out 语句之前将其所有结果合并到一个数组中?

【问题讨论】:

【参考方案1】:

嗯,经过一番研究,发现这可能是一个解决方案>

regx = re.compile("^("+"|".join('ab')+')')
myinvcol.insertMany(mydb.runCommand(

 'aggregate': "DirectIndex",
    'pipeline': 
    [
     "$match":  "words.word": regx  ,
     "$unwind": "$words" ,
     "$match":  "words.word": regx  ,
     "$group":  "_id":  "word":"$words.word", "count":"$words.count", 'document' : '$document'   ,
     "$group": 
        "_id": '$substr':[''.join('ab'),0,len(''.join('ab'))],
        "words": 
            "$push": 
                "word": "$_id.word",
                "count":"$_id.count",
                'document' : '$_id.document'
            
        
    ,
    '$out':"InverseIndex"
]).result)

(在这里找到mongoDB: how to reverse $unwind) 但是在这里,mongo 很糟糕。 out 参数覆盖集合的内容。所以如果我不止一次调用这个,之前的结果就会消失。 正如我在这里看到的:How do I append Mongo DB aggregation results to an existing collection?,Mongo 4.2 将有 $out 的特殊参数,称为模式:“replaceDocuments”。这将允许您将新内容附加到您的收藏中。但就目前而言,死路一条。

好吧,我尝试通过 mongo 内置的 map_reduce 函数调用来做到这一点:

mape = Code("function () "
    "var docName =this.document;"
                   "this.words.forEach(function(z) "
                   "z['document'] = docName;"
                   "var temp = z.word;"
                   "delete z.word;"
    "    emit(temp, 'documents':[z]);"
    "  );"
    "")
reduce = Code("function (key, values) "
           "  var total = [];"
           "  for (var i = 0; i < values.length; i++) "
           "for (var j=0;j<values[i]['documents'].length;j++)"
                "total.push('document':values[i]['documents'][j]['document'], 'count':values[i]['documents'][j]['count'], 'tf':values[i]['documents'][j]['tf']);"
           "  "
           "  return 'documents': total;"
       "")
finalizeFunction = Code("function (key, reducedVal) "
        "if('documents' in reducedVal)"
            "var normVal = Math.log((1+"+str(nrDocs)+")/(1+1+reducedVal.documents.length));"
            "reducedVal['idf']=normVal;"
            "return reducedVal; else return null;"
        ";")
result = mydb.DirectIndex.map_reduce(mape, reduce, 'merge':"InverseIndex",finalize=finalizeFunction)

这以某种方式满足了我的需求。缺点是速度。与手工实现的 MapReduce 相比(通过 dict 进行聚合+映射,其中 key 是 word),差异很大。无论如何,如果有人遇到这个问题,我只知道这两种方法来解决它。

【讨论】:

以上是关于如何在 pymongo 中将聚合操作的结果写为另一个集合中的一个文档的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中将对象数组向上转换为另一种类型的对象数组?

如何在swift(ios)中将字符串格式的日期转换为另一种字符串格式[重复]

如何在 C# 中将 datagridiew 中未包含的其他数据库值显示为另一种形式? [关闭]

在java中将日期从一种格式转换为另一种格式[重复]

我可以在 Java 中将布尔值转换为另一种数据类型吗

PyMongo 不返回聚合结果