当前位置: 首页 > 知识库问答 >
问题:

我如何确保我的聚合过滤出过期的mongo子文档?

皇甫鸿远
2023-03-14

我想计算当前活动的resetPassword(用户架构中的子文档)代码数。要激活代码,其到期日期必须大于当前日期。

这是我的用户模式。如果有人请求重置密码,我们将把一个新的{code:X,expiresAt,createdAt}对象推送到数组中。

id: { type: String, unique: true },
resetPassword: [
  {
    code: String,
    expiresAt: Date,
    createdAt: Date,
  },
],

我在尝试对活动重置代码的总数求和时遇到问题。下面是我正在运行的查询,它返回一个空数组。。。请注意,如果要删除resetPassword。expiresAt:{$gt:nowdateinmillizes()}match节,它将返回所有代码。我试着将这个匹配语句移出初始$match阶段,然后进行放松

[
  {
    $match: {
      "id": userId,
      'resetPassword.expiresAt': {
        $gt: nowDateInMillisec(),
      },
    },
  },
  {
    $group: {
      _id: '$id',
      totalValidResetCodes: {
        $sum: {
          $size: '$resetPassword',
        },
      },
    },
  },
]

这将返回一个空数组,即使我已将到期日期设置为将来的日期。

我还尝试了以下同样的结果(注意我如何在管道中添加$unwind和另一个$match)

[
  {
    $match: {
      "id": userId,
    },
  },
  {
    $unwind: '$resetPassword',
  },
  {
    $match: {
      'resetPassword.expiresAt': {
        $gt: nowDateInMillisec(),
      },
    }
  },
  {
    $group: {
      _id: '$id',
      totalValidResetCodes: {
        $sum: {
          $size: '$resetPassword',
        },
      },
    },
  },
]
  • nowDateInMillisec()-这只是以毫秒为单位返回当前日期

我做错了什么?

共有3个答案

燕寒
2023-03-14

@乔在评论中回答了我的问题。他暗示在匹配过滤器中使用从纪元时间算起的毫秒是行不通的,因为我在Mongoose模式中使用了Date类型。

因此,我没有这样做:$gt:nowDateInMillisec(),我只是使用了一个Date类型,比如:$gt:newdate(),

杭泉
2023-03-14

下面是我的研究,当以mongoDB格式存储的日期格式也应该工作毫秒。下面的测试时间长达一分钟。

> db.users13.find().pretty();
{
        "_id" : ObjectId("5f4e03768379a4e3f957641d"),
        "id" : "johnc",
        "resetPassword" : [
                {
                        "code" : "abc",
                        "expiresAt" : ISODate("2020-09-02T09:11:18.394Z"),
                        "createdAt" : ISODate("2020-09-01T08:11:18.394Z")
                },
                {
                        "code" : "mno",
                        "expiresAt" : ISODate("2020-08-25T09:26:18.394Z"),
                        "createdAt" : ISODate("2020-08-25T08:11:18.394Z")
                }
        ]
}
{
        "_id" : ObjectId("5f4e06938379a4e3f957641f"),
        "id" : "katey",
        "resetPassword" : [
                {
                        "code" : "j2c",
                        "expiresAt" : ISODate("2020-09-02T08:48:18.394Z"),
                        "createdAt" : ISODate("2020-09-01T08:11:18.394Z")
                },
                {
                        "code" : "rml",
                        "expiresAt" : ISODate("2020-09-01T08:26:18.394Z"),
                        "createdAt" : ISODate("2020-09-01T08:11:18.394Z")
                }
        ]
}
> db.users13.aggregate([ 
   {$unwind:"$resetPassword"}, 
   {$match:{"resetPassword.expiresAt":{$gt:ISODate()}}} 
 ]).pretty();
{
        "_id" : ObjectId("5f4e03768379a4e3f957641d"),
        "id" : "johnc",
        "resetPassword" : {
                "code" : "abc",
                "expiresAt" : ISODate("2020-09-02T09:11:18.394Z"),
                "createdAt" : ISODate("2020-09-01T08:11:18.394Z")
        }
}
{
        "_id" : ObjectId("5f4e06938379a4e3f957641f"),
        "id" : "katey",
        "resetPassword" : {
                "code" : "j2c",
                "expiresAt" : ISODate("2020-09-02T08:48:18.394Z"),
                "createdAt" : ISODate("2020-09-01T08:11:18.394Z")
        }
}
> ISODate()
ISODate("2020-09-01T08:31:37.059Z")
>
隆钊
2023-03-14

你可以在$project中尝试$减少,而不是你的所有进程,你需要从这个now返回ISOdate DateInMillisec()

db.collection.aggregate([
  { $match: { id: 1 } },
  {
    $project: {
      totalValidResetCodes: {
        $reduce: {
          input: "$resetPassword",
          initialValue: 0,
          in: {
            $add: [
              "$$value",
              {
                $cond: [
                  { $gt: ["$$this.expiresAt", nowDateInMillisec()] },
                  // If you really want to pass timestamp then try below line
                  // { $gt: ["$$this.expiresAt", { $toDate: nowDateInMillisec() }] },
                  1,
                  0
                ]
              }
            ]
          }
        }
      }
    }
  }
])

游乐场

 类似资料:
  • 问题内容: 我正在尝试过滤存储桶中的嵌套聚合。 对应: 索引数据: 我正在使用此查询和聚合定义 我从聚合结果中得到的是: 我在筛选存储桶列表时遇到了麻烦,因为它们只能提供所提供的事件ID,因此结果应类似于: 问题答案: 您快到了,只需要在聚合中添加过滤器即可,如下所示: 原因是您的查询将正确选择具有指定事件ID的嵌套事件的所有文档,但是,汇总将对所有选定文档中的所有嵌套事件进行处理。因此,您还需要

  • 问题内容: 我要实现的目标:我不希望查询过滤器过滤“年龄”聚合,并且希望能够对其应用过滤器。 因此,如果我从以下查询开始: 我的聚合“ young_age”将同时被filter_1和filter_2过滤。我不希望我的汇总被filter_1过滤。 在查看文档时,我认为全局聚合可以解决我的问题,因此我编写了以下查询: 但是然后elasticsearch抱怨我的filter_2: “”“在[global

  • 问题内容: 我对Elasticsearch世界真的很陌生。 比方说,我有两个字段嵌套聚集:与: 这段代码可以完美地工作,并且给我这样的东西: 现在,我需要排除所有小于1000的聚合结果,而改为: 是否可以在查询正文中设置此需求?还是我必须在调用者布局中执行过滤器(在我的情况下为javascript)? 提前致谢 问题答案: 下次,M’sieur Toph’:RTFM! 我真的很傻:问了30秒后,我

  • 问题内容: 我认为这很可能非常简单,但是我找不到关于如何在其网站上显示的’filterText’之外添加过滤器的清晰文档。我想做的就是这样简单: 编辑:或者也许我可以以某种方式过滤数据源?我尝试了这个: 但这会引发很多错误。 问题答案: 我发现了一种即时更新的方法。基本上,我保留了所有数据的隐藏集,并且在接收到新数据或更改过滤器后-我将此过滤器应用于完整数据集,并将网格交给过滤后的版本。 这使我可

  • 问题内容: 如何在$ lookup之后添加过滤器,或者有其他方法可以执行此操作? 我的数据收集测试是: 我选择ID 100并汇总孩子: 我回来了: 但我只希望与“值:1”匹配的子项 最后,我希望得到以下结果: 问题答案: 这里的问题实际上是关于一些不同的东西,根本不需要。但是,对于仅从“$lookup之后过滤”标题到达此处的任何人,这些都是适合您的技术: MongoDB 3.6-子管道 较早-$

  • 我有一个返回一组文档(100)的查询。我想对这些应用一个聚合,因为这些是最相关的。当我尝试聚合时,它返回所有结果的聚合,而不是前100个结果的聚合。