【问题标题】:Search nested array for certain criteria在嵌套数组中搜索某些条件
【发布时间】:2014-06-17 00:17:36
【问题描述】:

我有一个包含图像数组的报告文档。每个图像内部都有一个缩略图数组,用于跟踪我为图像生成的缩略图。

{
  "_id" : ObjectId("536021ba9b319f5195000004"),
  "images": [{
    "name": "some_image.jpg",
    "width": 1200,
    "height": 1200,
    "thumbnails": [{
      "name": "some_image_150.jpg",
      "size": 150
    }]  
  }]
}

现在假设我要生成以下缩略图大小:

[150, 320, 800]

有没有一种方法可以查询报告集合并取回所有未生成所有正确缩略图的报告? IE。在上面的示例中,查询将返回示例文档,因为它的图像不包含所有正确的附件。

最好的情况是只获取未生成所有缩略图的图像,即如果一个报告有 2 个图像,一个图像具有所有缩略图,而另一个图像没有,那么只获取需要缩略图的图像会很好。

我尝试过使用聚合来展开图像数组,这样我就可以匹配事物。但是,我在尝试将数组 [150, 320, 800] 中的数字与缩略图中的文档匹配时遇到问题。

编辑:

我还需要确定是否不应创建拇指。 IE。如果我的原始图像是 350x350,那么我不应该创建 800x800 的缩略图。因此,即使 800 在我的缩略图集中,我也只需要从该缩略图集中获取小于原始图像宽度和高度的值。

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    我相信以下内容应该适用于您的场景:

    db.mycollection.find( {"images.thumbnails.size": {$not: {"$all": [150, 320, 800]}}  })
    

    这应该为您提供不具有这些缩略图大小中的一种或多种的任何文档。

    【讨论】:

      【解决方案2】:

      您可能希望处理 $all 运算符与 $not 结合的否定情况:

      db.collection.find({
          "images.thumbnails.size": {
              "$not": { "$all": [ 150, 320, 800 ] }
          }
      })
      

      可能在 MongoDB 2.6 之前的版本中,由于$all 的逻辑发生变化,您可能需要对此进行调整,但同样的事情是使用$and 构造的:

      db.collection.find({
          "$and": [
              { "$ne": { "images.thumbnail.size": 150 } },
              { "$ne": { "images.thumbnail.size": 320 } },
              { "$ne": { "images.thumbnail.size": 800 } }
          ]
      })
      

      当然请注意,这些语句匹配“文档”而不是“图像”数组的元素,以实际过滤您需要将其应用于聚合的那些:

      db.collection.aggregate([
          // Match the documents meeting the conditions
          { "$match": {
              "images.thumbnails.size": {
                  "$not": { "$all": [ 150, 320, 800 ] }
              }
          }},
      
          // Unwind the images array
          { "$unwind": "$images" },
      
          // Filter out any array elements that do not match
          { "$match": {
              "images.thumbnails.size": {
                  "$not": { "$all": [ 150, 320, 800 ] }
              }
          }},
      
      
          // Optional: Projection re-shaping
          { "$project": {
              "_id": {
                  "_id": "$_id",
                  "images": {
                      "name": "$images.name",
                      "width": "$images.width",
                      "height": "$images.height"
                  }
              },
              "thumbs": "$images.thumbnails"
          }},
      
          // Optional: unwind the thumbnails
          { "$unwind": "$thumbs" },
      
          // Optional: group back only the sizes
          { "$group": {
              "_id": "$_id",
              "thumbs": { "$push": "$thumbs.size" }
          }},
      
          // Optional: Project with the difference on the set
          { "$project": {
              "_id": "$_id._id",
              "images": {
                  "name": "$_id.images.name",
                  "width": "$_id.images.width",
                  "height": "$_id.images.height",
                  "missingThumbs": { "$setDifference": [
                       [ 150, 320, 800 ],
                       "$thumbs"
                  ]}
              }
          }},
      
          // Restore the images array
          { "$group": {
              "_id": "$_id",
              "images": { "$push": "$images" }
          }}
      
      ])
      

      所以这使用$setDifference 更进一步,并告诉您您正在测试的哪些“缩略图大小”不存在。该阶段是可选的,因为该运算符仅适用于 MongoDB 2.6 及更高版本,因此只需删除标记为“可选:”的阶段即可过滤“图像”数组条目。

      您也可以在 2.6 之前的版本中进行“差异”匹配,但这涉及的内容要多一些,但您可能想尝试解决这部分问题。


      至于您的全代编辑,这里将是完整列表:

      db.collection.aggregate([
          // Match the documents meeting the conditions
          { "$match": {
              "images.thumbnails.size": {
                  "$not": { "$all": [ 150, 320, 800 ] }
              }
          }},
      
          // Unwind the images array
          { "$unwind": "$images" },
      
          // Filter out any array elements that do not match
          { "$match": {
              "images.thumbnails.size": {
                  "$not": { "$all": [ 150, 320, 800 ] }
              }
          }},
      
          // Projection re-shaping
          { "$project": {
              "_id": {
                  "_id": "$_id",
                  "images": {
                      "name": "$images.name",
                      "width": "$images.width",
                      "height": "$images.height"
                  }
              },
              "thumbs": "$images.thumbnails"
          }},
      
          // unwind the thumbnails
          { "$unwind": "$thumbs" },
      
          // group back only the sizes
          { "$group": {
              "_id": "$_id",
              "thumbs": { "$push": "$thumbs.size" }
          }},
      
          // Project missingThumbs
          { "$project": {
              "missingThumbs": { "$setDifference": [
                   [ 150, 320, 800 ],
                   "$thumbs"
              ]}
          }},
      
          // Unwind the missing thumbs
          { "$unwind": "$missingThumbs" },
      
          // Project a size test
          { "$project": {
              "missingThumbs": 1,
              "larger": { "$gte": [ 
                  "$_id.images.width",
                  "$missingThumbs"
              ]}
          }},
      
          // Match the size test
          { "$match": { "larger": true }},
      
          // Group back the missing thumbs
          { "$group": { 
              "_id": "$_id",
              "missingThumbs": { "$push": "$missingThumbs" }
          }},
      
          // Project the images entry
          { "$project": {
              "_id": "$_id._id",
              "images": {
                  "name": "$_id.images.name",
                  "width": "$_id.images.width",
                  "height": "$_id.images.height",
                  "missingThumbs": "$missingThumbs"
              }
          }},
      
          // Restore the images array
          { "$group": {
              "_id": "$_id",
              "images": { "$push": "$images" }
          }}
      
      ])
      

      这里没有什么可选的,因为您显然会使用这些功能来检测您还没有的缩略图。额外的步骤是比较丢失拇指的大小和图像的大小。任何未被检测为“更大”的内容都将被排除在外。

      【讨论】:

      • 太棒了!但是,我对聚合管道中的第 1 步和第 3 步感到困惑。他们似乎在做同样的事情。 IE 过滤掉所有不在我的集合中的缩略图。为什么我都需要?
      • @lostintranslation 首先是过滤不匹配的文档,因此对它们进行处理毫无意义。其次是在找到数组内容后,您从文档中取出不匹配的元素。跳过第一个匹配会导致不需要的额外工作量,因此它是在数组内匹配时进行优化的最佳方式。这也是为什么在过滤内部数组方面聚合不同的原因。
      • 我想我现在明白了。首先匹配包含所有拇指的文档。第二个展开。第三个过滤掉作为文档匹配一部分的拇指。
      • @lostintranslation 没错。这就是您可以使用 find 获得的结果之间的本质区别,因为文档仍将包含不匹配的数组条目。但同样,这样做两次的原因是您没有处理集合中的文档,这些文档甚至与 $unwind 的条件都不匹配。与整个系列相比,该部分可能非常昂贵,因此您也要先匹配。无论如何,这取决于你想要什么。我一般推测您不需要已经具有所需缩略图大小的数组条目。
      • 关于如何动态限制我想要生成的拇指组的任何想法,以使数组的所有值都小于 image.width 或 image.height。 IE。我没有放大缩略图,所以如果我的图像是 150x150,我不会创建 320 或 800 的缩略图。我可以通过 mongo [150, 320, 800] - 并且值大于我的图像宽度或图像高度吗? -检查帖子中的编辑
      猜你喜欢
      • 2015-09-26
      • 1970-01-01
      • 2018-07-28
      • 2013-01-18
      • 1970-01-01
      • 2013-12-18
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      相关资源
      最近更新 更多