【问题标题】:Is it possible to apply a different aggregation projection to each document in the aggregation pipeline?是否可以对聚合管道中的每个文档应用不同的聚合投影?
【发布时间】:2020-08-31 10:59:05
【问题描述】:

考虑这个集合:

[
  {
    id: 1,
    nest: [
      object: {
        date: '2020-04-19T00:00:00.000Z'
      },
      object: {
        date: '2020-04-20T00:00:00.000Z'
      },
      object: {
        date: '2020-04-21T00:00:00.000Z'
      }
    ]
  },
  {
    id: 2,
    nest: [
      object: {
        date: '2020-04-22T00:00:00.000Z'
      },
      object: {
        date: '2020-04-23T00:00:00.000Z'
      },
      object: {
        date: '2020-04-24T00:00:00.000Z'
      },
      object: {
        date: '2020-04-25T00:00:00.000Z'
      }
    ]
  }
]

我想生成一个与原始集合具有相同形状的聚合,但根据特定文档限制nestobjects 的数量。例如,对于集合的第一个成员,我想要date 小于或等于"2020-04-20T00:00:00.000Z" 的对象,而对于第二个成员,我想要date 小于或等于"2020-04-24T00:00:00.000Z" 的对象。所以这将是我想要的输出:

[
  {
    id: 1,
    nest: [
      object: {
        date: '2020-04-19T00:00:00.000Z'
      },
      object: {
        date: '2020-04-20T00:00:00.000Z'
      }
    ]
  },
  {
    id: 2,
    nest: [
      object: {
        date: '2020-04-22T00:00:00.000Z'
      },
      object: {
        date: '2020-04-23T00:00:00.000Z'
      },
      object: {
        date: '2020-04-24T00:00:00.000Z'
      }
    ]
  }
]

我得到的最远的将静态日期应用于集合的所有成员,如下所示:

{
  $project: {
    nest: {
      $filter: {
        input: "$nest",
        as: "nested",
        cond: { $lte: [ "$$nested.date", <date-goes-here> ] }
      }
    }
  }
}

这会将我使用的任何日期应用于集合的所有成员,这不是我想要的。

我怎样才能达到我想要的输出?谢谢!

更新

这适用于返回 1:1 或群聊的聊天的端点。集合的每个成员都是一个聊天,nest 对象是特定聊天中的消息数组。我想对客户端请求群聊时返回的消息数进行分页,所以我的想法是只获取客户端指定日期之前的消息。客户端可以发送一个请求,说对于聊天 1(这是一个群聊),它希望在 "2020-04-20T00:00:00.000Z" 或之前发送消息,对于聊天 2(也是一个群聊),它希望在 @ 或之前发送消息987654334@。我使用$match 获取客户端请求的聊天,我想使用$project 过滤掉客户端为该聊天指定的日期之后的消息。

【问题讨论】:

  • 如果你有更多的文件在收集呢?应该从 3 个及以上应用什么条件?
  • 这取决于集合的每个成员。我试图简化场景,但基本上对于具有某些属性的文档我应用此过滤器,而对于其他我不应用。我使用$cond 做到了这一点。但问题是,对于每个需要过滤器的文档,它都需要自己的唯一日期。
  • 该条件的日期是否存在于文档中,或者它是否可以从文档中的某些内容推导出来?您可能希望包含如何计算日期的逻辑。
  • @TheeSritabtim 我添加了更多细节,如果您需要更多信息,请告诉我。谢谢!
  • $filtercond中,可以指定条件为:(id = 1 AND nested.date lte "2020-04-20") OR (id = 2 AND nested.date lte "2020-04-24")

标签: mongodb mongoose aggregation-framework


【解决方案1】:

是的,这是可能的,但要做到这一点,您必须创建一个 JSON 对象,基本上是基于用户输入的键值对,例如

datesHash = { chatId:date,chatId2:date2} // these id's and dates will be based on user input as you mentioned above.

然后在上面的聚合中巧妙地使用它

{
  $project: {
    nest: {
      $filter: {
        input: "$nest",
        as: "nested",
        cond: { $lte: [ "$$nested.date", datesHash["$_id"] ] }
      }
    }
  }
}

我已尝试在工作示例 https://play.db-ai.co/m/Xr3LWwbYvgABFVSC 上重新创建您的解决方案(这仅供参考,并非确切的解决方案)

【讨论】:

  • 感谢您的回答。我无法让它工作。如果您使用datesHash["$_id"] 而不是datesHash["$id"],您能否确认它是否适合您? _id 是对象 ID,这就是我实际使用的,到目前为止它不起作用(我得到一个空结果,因为根本没有投影)。
  • 哦,那是错字,我会编辑它,是的,如果你使用 $_id 它应该会很好,因为我已经在多个项目中尝试过这种方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 2023-04-10
相关资源
最近更新 更多