【问题标题】:Mongodb aggregation lookup with conditions带有条件的MongoDB聚合查找
【发布时间】:2018-07-09 03:35:04
【问题描述】:

我有一个名为article_category 的集合,它存储所有article_id 属于category_id 的类别,数据格式如下。

集合 1:article_category

{
  "article_id": 2015110920343902,
  "all_category_id": [5,8,10]
}

然后我有另一个名为 article 的集合,其中存储了我所有的帖子

集合 2:文章

{
  "title": "This is example rows in article collection"
  "article_id": 2015110920343902,
},
{
  "title": "Something change"
  "article_id": 2015110920343903,
},
{
  "title": "This is another rows",
  "article_id": 2015110920343904,
}

现在我想执行 MongoDB 查询以找到 titleregex,而 category_id 必须等于 8。这是我的查询,但不起作用。

db.article.aggregate(
{
  $match: 
  {
    title: 
    {
       $regex: /example/
    }
  }
},
{
    $lookup:
       {
         from: "article_category",
         pipeline: [
            { $match: { category_id: 8 } }
         ],
         as: "article_category"
       }
  }
)

以上查询只显示regex匹配但category_id不匹配的记录。

有什么想法吗?

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    首先是all_category_id,而不是category_id。其次,您不链接文章 - 所有文档都将具有完全相同的 article_category 数组。最后,您可能想要过滤掉没有匹配类别的文章。条件管道应该看起来更像这样:

    db.article.aggregate([
      { $match: {
          title: { $regex: /example/ }
      } },
      { $lookup: {
        from: "article_category",
        let: {
          article_id: "$article_id"
        },
        pipeline: [
          { $match: {
              $expr: { $and: [
                  { $in: [ 8, "$all_category_id" ] },
                  { $eq: [ "$article_id", "$$article_id" ] }
              ] }
          } }
        ],
        as: "article_category"
      } },
      { $match: {
        $expr: { $gt: [
          { $size: "$article_category"},
          0
        ] }
      } }
    ] )
    

    更新:

    如果您不匹配 article_id,则 $lookup 将导致与所有文章相同的 article_category 数组。

    假设您的 article_category 收藏有另一个文档:

    {
      "article_id": 0,
      "all_category_id": [5,8,10]
    }
    

    { $eq: [ "$article_id", "$$article_id" ] } 在管道中,生成的article_category

    [ 
      { 
        "article_id" : 2015110920343902, 
        "all_category_id" : [ 5, 8, 10 ] 
      } 
    ]
    

    没有:

    [ 
      { 
        "article_id" : 2015110920343902, 
        "all_category_id" : [ 5, 8, 10 ] 
      },
      {
        "article_id": 0,
        "all_category_id": [ 5, 8, 10 ]
      }
    ]
    

    如果您需要后者,那么查找请求会更简单:

    db.article.find({ title: { $regex: /example/ } })
    

    db.article_category.find({ all_category_id: 8 })
    

    【讨论】:

    • 我不明白你为什么要比较article_id,我只需要查询title 在哪里包含sample AND article_category.all_category_id 等于8
    • @vietnguyen09 因为and 暗示两者都应该匹配。查看更新。
    • 您的查询很完美,而且效果很好,但我花了 26 秒才得到结果。我一直在为article_idall_category_id 添加索引,但没有运气。你能建议我如何让它更快吗?我添加了限制 10,但结果仍然需要 3 秒
    • @vietnguyen09,试试 Veeram 的。您在这里并不需要条件查找。我之所以保留它,是因为您明确询问了如何在您的情况下使用条件查找。我相信正则表达式是最耗时的,但可以肯定地说,您需要提供带有allPlansExecution 选项的explain 命令的输出。
    【解决方案2】:

    这里有几处不正确。 category_id 应该是 all_category_id。使用$lookup 中的连接条件并将$match 移动到$lookup 阶段之外,并使用$unwind 进行optimized 查找。

    $project 与排除一起使用以从最终响应中删除查找的字段。 类似{$project:{article_category:0}}

    试试

    db.article.aggregate([
      {"$match":{"title":{"$regex":/example/}}},
      {"$lookup":{
        "from":"article_category",
        "localField":"article_id",
        "foreignField":"article_id",
        "as":"article_category"
      }},
      {"$unwind":"$article_category"},
      {"$match":{"article_category.all_category_id":8}}
    ])
    

    对于不相关的子查询试试

    db.article.aggregate([
      {"$match":{"title":{"$regex":/example/}}},
      {"$lookup":{
        "from":"article_category",
        "pipeline":[{"$match":{"all_category_id":8}}],
        "as":"categories"
      }},
      {"$match":{"categories":{"$ne":[]}}}
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-11
      • 2017-02-22
      • 2020-11-23
      • 2020-02-06
      • 2019-07-16
      • 2023-03-16
      • 1970-01-01
      相关资源
      最近更新 更多