【问题标题】:MongoDB aggregation: flatten array property into root arrayMongoDB聚合:将数组属性展平为根数组
【发布时间】:2021-01-25 02:42:57
【问题描述】:

我正在开发一个使用$graphLookUp 递归查找cmets 线程的功能,我几乎拥有它。 (虽然有点复杂,但它确实有效!)

我需要的最后一步是: 不要将嵌套的 posteriorThread 作为根数组 ($$ROOT) 的属性,而是将其合并到根本身。

  • 聚合代码:
const posteriorThread = await Comment.aggregate([
  {
    $match: {
      _id: post.threadDescendant
    }
  },

  {
    $graphLookup: {
      from: 'baseposts',
      startWith: '$threadDescendant',
      connectFromField: 'threadDescendant',
      connectToField: '_id',
      as: 'posteriorThread'
    }
  },

  {
    $unwind: '$posteriorThread'
  },

  {
    $sort: { 'posteriorThread.depth': 1 }
  },

  {
    $group: {
      _id: '$_id',
      posteriorThread: { $push: '$posteriorThread' },
      root: { $first: '$$ROOT' }
    }
  },

  {
    $project: {
      'root.posteriorThread': 0
    }
  },

  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          {
            posteriorThread: '$posteriorThread'
          },
          '$root'
        ]
      }
    }
  }
]);
  • 电流输出
 OUTPUT: posteriorThread
[
  {
    _id: '5f7eab40575e6fc56ee07604',
    onModel: 'BasePost',
    depth: 1,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 0',
    isThread: true,
    threadDescendant: '5f7eabad575e6fc56ee07607',
    posteriorThread: [
      {
        _id: '5f7eabad575e6fc56ee07607',
        onModel: 'Comment',
        depth: 2,
        user: '5f5da45245c07cc06e51b09f',
        text: 'thread 1',
        isThread: true,
        threadDescendant: '5f7eac82575e6fc56ee07609'
      },
      {
        _id: '5f7eac82575e6fc56ee07609',
        onModel: 'Comment',
        depth: 3,
        user: '5f5da45245c07cc06e51b09f',
        text: 'thread 2',
        isThread: true
      }
    ]
  }
];

  • 期望的输出
OUTPUT: posteriorThread 
[
  {
    _id: '5f7eab40575e6fc56ee07604',
    onModel: 'BasePost',
    depth: 1,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 0',
    isThread: true,
    threadDescendant: '5f7eabad575e6fc56ee07607'
  },
  {
    _id: '5f7eabad575e6fc56ee07607',
    onModel: 'Comment',
    depth: 2,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 1',
    isThread: true,
    threadDescendant: '5f7eac82575e6fc56ee07609'
  },
  {
    _id: '5f7eac82575e6fc56ee07609',
    onModel: 'Comment',
    depth: 3,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 2',
    isThread: true
  }
];

我可以在常规 js 中聚合后完成此操作,但我更愿意在聚合中完成所有操作。 需要替换的部分是 mergeObjects 位并替换为其他内容或 group 聚合并采取不同的策略,但我不确定该放置什么。 另外,如果您有任何其他建议来使这个更清洁,我会全力以赴。

提前致谢。

【问题讨论】:

    标签: javascript mongodb mongoose aggregate


    【解决方案1】:

    真的很有挑战性。至少对我来说。而且非常有趣的案例。让我们试试我的解决方案。希望它有效..

    db.test.aggregate([
    
        // PREVIOSU STEPS YOU ALREADY DID
    
        {
            $group: {
                _id: "$_id",
                items: {$push: "$$ROOT"},
                subItems: {$first: "$posteriorThread"}
            }
        },
        {
            $project: {
                "items.posteriorThread": 0
            }
        },
        {
            $addFields: {
                allItems: {
                    $concatArrays: ["$items", "$subItems"]
                }
            }
        },
        {
            $group: {
                _id: null,
                mergedItems: {$push: "$allItems"}
            }
        },
        {
            $unwind: "$mergedItems"
        },
        {
            $unwind: "$mergedItems"
        },
        {
            $replaceRoot: {
              newRoot: "$mergedItems"
            }
        }
    
    ])
    

    【讨论】:

    • 嘿,您的解决方案不起作用,因为 subItems 不是数组,因此无法连接,但它确实让我更接近了!我现在基本上有了它,但是$replaceRoot 仍然给我留下了一个嵌套数组,但这没什么大不了的,因为我可以在聚合后得到正确的解决方案。
    • 如果您想查看我的最终解决方案,请查看我的答案。
    • 很高兴听到您找到了解决方案。我不知道为什么我的解决方案不起作用。我实际上是在处理您的当前输出。这意味着您必须使用您已经执行的步骤,然后在现有阶段之后添加我的管道阶段。在您的当前输出中,后线程是一个项目数组。所以它应该奏效了。无论如何,我实际上将您的当前输出存储到一个集合中,然后我尝试了我的步骤。它给了我结果。无论如何,这个问题真的很有趣..
    • 嗯,这很奇怪。是的,subItems 使用 $first 返回一个对象,所以当我转到 $concat 时,它会抛出错误,类似于“无法连接和对象”。但是,是的,我认为添加一个简单的线程功能将是几行代码,它变成了一整天的聚合和错误!再次感谢你的帮助;它真的让我走上了正确的道路。如果您想复制并粘贴我的答案,我会给您答案。
    • 哈哈..不不。并不需要。请。我很高兴它真的有帮助!谢谢你的提问。老实说,我不知道该怎么做,这对我来说也是实验性的。问题陈述很有趣。所以我开始研究它,我也从中吸取了一些教训。
    【解决方案2】:

    感谢@Sunil K Samanta 引导我朝着正确的方向前进。这不是最漂亮的解决方案,但它确实给了我正确的解决方案。

    const posteriorThread = await Comment.aggregate([
      {
        $match: {
          _id: post.threadDescendant
        }
      },
    
      {
        $graphLookup: {
          from: 'baseposts',
          startWith: '$threadDescendant',
          connectFromField: 'threadDescendant',
          connectToField: '_id',
          as: 'posteriorThread'
        }
      },
    
      {
        $unwind: '$posteriorThread'
      },
    
      {
        $sort: { 'posteriorThread.depth': 1 }
      },
    
      {
        $group: {
          _id: '$_id',
          items: { $push: '$$ROOT.posteriorThread' },
          root: { $push: '$$ROOT' },
        },
      },
    
      {
        $project: {
          items: 1,
          root: { $slice: ['$$ROOT.root', 0, 1] },
        },
      },
    
      {
        $project: {
          'root.posteriorThread': 0,
        },
      },
    
      {
        $addFields: {
          allItems: {
            $concatArrays: ['$root', '$items'],
          },
        },
      },
    
      {
        $replaceRoot: {
          newRoot: {
            full_posterior: '$$ROOT.allItems',
          },
        },
      },
    ])
    )[0].full_posterior;
    

    【讨论】:

    • [0].full_posterior 是我们首先要避免的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 2023-03-08
    • 2020-04-17
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多