mongodb:返回子文档并跟踪父级

时间:2017-08-07 08:57:08

标签: mongodb aggregation-framework

我有一组推文,我试图在根级别(类似于引用的推文)输出转发到新的集合,以便稍后使用转储和恢复将它们与原始集合合并。 转发状态是推文文档中的子文档,可能有多条推文转发同一条推文。 如何在根级别进行转发并添加一个名为'转发_by'包含转发它的所有推文的ID?

请记住,我使用tweet id作为主索引(_id),以避免在组合(mongorestore)集合时创建重复项。

我的收藏品有以下形式:

{
    "_id" : "123456",
    "other_fields1" : "values1",
    "retweeted_status" : {
                          "retweet_id": "159753",
                          "other_fields2" : "values2",
                          }
}

理想的输出预计如下:

{
    "_id" : "159753",
    "other_fields2" : "values2",    
    "retweeted_by" : [ "123456", "974631", "121212"]
}

编辑以澄清:

子文档中的字段(other_fields2)是多个字段(~28),这些字段并不存在于其他推文中

1 个答案:

答案 0 :(得分:0)

好的..所以我终于找到了我的问题的解决方案..我不确定这是否是最好的方法:

db.tweets.aggregate([
{
    $match: { retweeted_status: {$exists: true}} 
},
{ 
    $addFields: { 'retweeted_status.retweeted_by' : '$_id', 'retweeted_status._id' : '$retweeted_status.id_str'} 
},
{
   $replaceRoot: { newRoot: '$retweeted_status'} 
},
{ 
    $group: { _id: '$_id',  doc: { '$first': '$$ROOT' }, retweeted_by: {$addToSet: '$retweeted_by'}}
},
{
    $addFields: { 'doc.retweeted_by' : '$retweeted_by'}
},
{
    $replaceRoot: { newRoot: '$doc'}
},
{
    $project: { id: 0 , id_str: 0 }
},
{
    $out: 'retweets'
}
], {allowDiskUse: true})

最初,每个文件(推文)都有以下形式:

{parent,{subdocument}}

首先匹配retweeted_status(子文档)的存在,然后在通过retweeted_status id进行分组之前,我添加了一个带有父推文id的字段:

{parent,{subdocument,parent_id}}

然后用修改后的子文档替换了root:

{subdocument,parent_id}

然后,我按新根的_id分组,获取该组的第一个文档,并添加了一个新的累加器集(retweeted_by)。 (不是$ push,因为twitter API有时会发送重复项)

到目前为止,根文档包含_id,嵌入在字段'doc'中的转发文档,以及包含父项的数组:

{doc {subdocument,parent_id},[parent_ids]}

接下来,我将parents数组添加为doc中的一个字段,(覆盖之前添加的retweeted_by字段):

{doc {subdocument,[parent_ids]},[parent_ids]}

然后用新文档替换父(root)。然后排除包含与_id相同数字的字段:

{subdocument,[parent_ids]}