搜索嵌套数组以获取特定条件

时间:2014-04-30 15:25:59

标签: mongodb mongoose mongodb-query aggregation-framework

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

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

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

[150, 320, 800]

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

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

我已经尝试过使用聚合来解开图像数组,这样我就可以匹配东西了。但是我遇到了一个问题,试图将我的数组[150,320,800]中的数字与缩略图中的文档进行匹配。

修改

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

2 个答案:

答案 0 :(得分:3)

我认为以下情况应该适用于您的情况:

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

这可以为您提供任何不具有一个或多个缩略图大小的文档。

答案 1 :(得分:1)

您可能希望处理$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及更高版本获得,因此只需删除标记为“Optional:”的阶段,以允许此过滤“images”数组条目。

你也可以在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" }
    }}

])

此处没有可选项,因为您显然会使用这些功能来检测您尚未拥有的缩略图。附加步骤用于比较缺失拇指的大小和图像的大小。任何未被检测为“较大”的东西都将被排除在外。