Mongodb使用多个过滤器聚合

javapedia.net

我正在学习Mongodb聚合函数,并且正在研究查询。我的文档如下所示。

[
    {
        "_id": 17,
        "members": [{
                "email": "[email protected]",
                "status": "pending",
                "joined": ISODate("2020-05-20T02:04:00Z")
            },
            {
                "email": "[email protected]",
                "status": "pending",
                "joined": ISODate("2020-05-20T02:36:00Z")
            }
        ],
        "messages": [{
                "c": "m1",
                "ts": ISODate("2020-05-20T02:04:15Z")
            },
            {
                "c": "m2",
                "ts": ISODate("2020-05-20T02:36:31Z")
            }
    
        ]
    }
]

每个文档都有2个数组:成员和消息。我需要过滤成员中的一个元素(使用电子邮件),并根据与“ messages.ts”属性匹配的“ members.joined”属性过滤消息。

我尝试了不同的方法,但尚未实现。在下面的查询中,我对日期ISODate(“ 2020-05-20T02:36:00Z”)进行了硬编码,而不是使用member.joined属性。如何编写优化查询以实现相同目的?

db.coll.aggregate([
  {
    $match: {
      _id: 17,
      "members.email": "[email protected]"
    }
  },
  {
    $project: {
      messages: {
        $filter: {
          input: "$messages",
          as: "messs",
          cond: {
            $gte: [
              "$$messs.ts",
              ISODate("2020-05-20T02:36:00Z") // supposed to have members.$.joined property here
            ]
          }
        }
      }
    }
  }
])

预期结果是应该打印的消息中的第二个元素。

谁-假面真灵魂

您可以尝试以下聚合查询中的任何一个:

db.collection.aggregate([
    {
      $match: { _id: 17, "members.email": "[email protected]" }
    },
    /** If you need `members` array as is i.e; unfiltered in response, So instead of expensive iteration on `members` array we can get `joined` value as like below */
    {
      $addFields: {
        messages: {
          $let: {
            vars: {
              messagesArr: {
                $reduce: {
                  input: "$messages",
                  initialValue: { data: [], joinedTime: { $arrayElemAt: [ "$members.joined", { $indexOfArray: [ "$members.email", "[email protected]" ] } ] } },
                  in: {
                    data: {
                      $cond: [ { $gte: [ "$$this.ts", "$$value.joinedTime" ] },
                               { $concatArrays: [ "$$value.data", [ "$$this" ] ] }, // If condition is met concat holding array with new object
                               "$$value.data" // If not just return the holding array, doesn't add current object to array
                      ]
                    },
                    joinedTime: "$$value.joinedTime" // maintaining joined value
                  }
                }
              }
            },
            in: "$$messagesArr.data" // return newly created array in `$reduce` using `$let`
          }
        }
      }
    }
  ])

测试: mongoplayground

参考: 聚合

因此,上面的查询将返回过滤后的messages数组和原始members数组。以防万一,如果您还需要members过滤,然后在以下$addFields阶段添加以下内容$match(我们假设这email是唯一的),这样做可以避免在大型数组上进行迭代:

{
    $addFields: {
      members: {
        $arrayElemAt: [
          "$members",
          {
            $indexOfArray: [
              "$members.email",
              "[email protected]"
            ]
          }
        ]
      }
    }
  }

当您执行上述操作时,members将是一个已过滤的对象。这样$reduce就可以了joinedTime: "$members.joined"

测试: mongoplayground

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章