【问题标题】:Mongodb aggregate query $skip $limit issues [duplicate]Mongodb聚合查询$skip $limit问题[重复]
【发布时间】:2019-10-22 04:32:27
【问题描述】:

我从我的应用中调用了一个查询,以向我提供来自我的数据库的分页结果

const query = [
  {
    "$match" : {
      "$or" : [
        { "expires_at" : { "$gt" : moment().toISOString() }},
        { "expires_at" : null }
      ],
      "vendor_category" : {
        "$nin" : ignoredCategories
      }
    }
  },
  {
    "$lookup": {
      "from": models.retailers.collection.name,
      "localField": "retailer",
      "foreignField": "_id",
      "as": "retailer"
    }
  },
  {
    "$lookup": {
      "from": models.categories.collection.name,
      "localField": "category",
      "foreignField": "_id",
      "as": "category"
    }
  },
  {
    "$sort": {
      "category.popularity" : -1,
      ...sortBy
    }
  },
  { "$unwind": "$retailer" },
  { "$unwind": "$category" },
  { "$skip" : skip },
  { "$limit" : limit }
]

这很有效,我的两个 $lookup$unwind 对象将其他集合加入到结果中,我的 $sort 对象正确地按产品类别流行度对根查询进行排序。

但是,我的 $match 对象仅返回大约 18 个(共 72 个)结果。除了当我运行const total = await models.products.countDocuments(query[0].$match) 时,这很好,所以使用该匹配查询计算文档,我得到 72。所以两者之间存在不匹配。

那么其余的结果会怎样呢?我在这个查询中做错了吗?这绝对是我写的第一个聚合查询,所以也许我只是完全错过了一些东西。欢迎任何提示/问题/优化!如果您需要更多信息,请告诉我。

编辑 这是扩展匹配查询的示例。当我使用Model.find 时,它工作正常,但由于我一直在隔离部分查询,这似乎是罪魁祸首。目的是仅提取过期时间大于当前时间的结果,或者该字段为空。数据来自刮板,有时我没有过期数据。我还排除了一系列类别,这是为了防止显示通过刮板但我不想出现在网站上的项目。

$match : {
       $or : [
         { expires_at : { $gt : moment().toISOString() }},
         { expires_at : null }
      ],
      vendor_category : {
        $nin : [ 'ID-6',   'ID-8', 'ID-283', 'ID-288', 'ID-354', 'ID-513', 'ID-654', 'ID-659', 'ID-33', 'ID-450', 'ID-497',  'ID-59', 'ID-404', 'ID-337']
      }
    }

【问题讨论】:

  • 是否有可能某些类别或零售商不存在于另一个集合中。是的,$unwind 是这里出现问题的原因。
  • docs.mongodb.com/manual/core/aggregation-pipeline-optimization 没有回答这个问题,但值得一读。你怎么知道第一阶段返回“大约 18 个结果”?
  • 所以我接受,你的问题只是关于 $match 查询?常规查询和聚合查询之间存在一些细微的实现差异,这可能会干扰这里。你能给我们举一个被忽略的类别的例子吗?另外,您确定“expires_at”将始终为“null”,还是根本不设置?
  • @BenSower 我更新了这个问题,提供了更多关于此的背景信息。当我完全删除匹配查询时,我得到了所有结果,分页工作正常。此外,当我将 vendor_category 查询留在那里时,它似乎也可以正常工作。所以$or 对象似乎是罪魁祸首。

标签: node.js mongodb mongoose


【解决方案1】:

好吧,在挖掘和挖掘之后,我找到了一个 github issue,它解决了我的问题,希望这将在未来对其他人有所帮助。使用Model.aggregate 时,Mongoose 不会转换它的参数。

如果您希望使用Model.aggregate 匹配日期,则必须将日期包装在new Date() 中。

最初我这样做是行不通的:{ expires_at : { $gte : moment().toISOString() }}

并将其更改为这样,有效:{ expires_at : { $gte : new Date(moment().toISOString()) }}

【讨论】:

  • 这就是我所说的“轻微的实现差异”。另一个是 ObjectIds 的处理,如果您不以聚合框架理解的方式传递它,有时可能会遇到问题。也请将您的答案标记为完整:-)
  • 只是想说你是完全正确的,我很感激你让我走上了这条路。一旦我开始隔离不同的对象,它们肯定是不同的,这有助于我对所有内容进行分类。谢谢大佬!
猜你喜欢
  • 2021-12-14
  • 1970-01-01
  • 2014-08-01
  • 2021-07-03
  • 2019-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多