MongoDB - 搜索子文档

时间:2016-04-14 16:53:33

标签: mongodb mongodb-query

我正在尝试在子文档中搜索。这是我的文档结构:

{
    _id: <ObjectID>,
    email: ‘test@emample.com’,
    password: ‘12345’,
    images: [
        {
            title: ‘Broken Hand’,
            description: ‘Here is a full description’,
            comments: [
                {
                    comment: ‘Looks painful’,
                }
            ],
            tags: [‘hand’, ‘broken’]
         }  
    ]
}

我希望能够找到所有具有特定标记的用户的所有图像,但我使用的查询只返回它找到的第一个带有该标记的图像:

db.site_users.find({'images.tags': "broken"}, {images: 1, images: {$elemMatch: { 'tags': 'broken'}}}).pretty()

有人可以指出我如何获得所有图像的正确方向吗?

2 个答案:

答案 0 :(得分:0)

您可以使用aggregation framework

db.site_users.aggregate([
    {$unwind: "$images"},
    {$match:{
        "images.tags": "broken"
    }}
])

答案 1 :(得分:0)

查询很好,因为它与文档匹配,但“投影”超出了您使用.find()所能做的范围,您需要.aggregate()并且需要注意不要删除“图像“数组中的项目,只有不匹配的”标签“。

理想情况下,您使用$filter内的$project对MongoDB 3.2执行此操作:

db.site_users.aggregate([
    { "$match": { "images.tags": "broken" }},
    { "$project": {
        "email": 1,
        "password": 1,
        "images": {
            "$filter": {
                "input": "$images",
                "as": "image",
                "cond": {
                    "$setIsSubSet": [["broken"], "$$image.tags"]
                }
            }
        }
    }}
])

或者可能使用与MongoDB 2.6兼容的$map$setDifference,只要“images”内容对于每个条目都是“唯一的”。这是由于“设置”操作,其中“集合”是“唯一的”:

db.site_users.aggregate([
    { "$match": { "images.tags": "broken" }},
    { "$project": {
        "email": 1,
        "password": 1,
        "images": {
            "$setDifference": [
                { "$map": {
                    "input": "$images",
                    "as": "image",
                    "in": {
                        "$cond": {
                            "if": { "$setIsSubSet": [["broken"], "$$image.tags" ] },
                            "then": "$$image",
                            "else": false
                        }
                    }
                }},
                [false]
            ]
        }
    }}
])

可以在早期版本的MongoDB中完成,但由于在阵列上处理$unwind的成本,最好避免使用它:

db.site_users.aggregate([
    { "$match": { "images.tags": "broken" }},
    { "$unwind": "$images" },
    { "$match": { "images.tags": "broken" }},
    { "$group": {
        "_id": "$_id",
        "email": { "$first": "$email" },
        "password": { "$first": "$password" },
        "images": { "$push": "$images" }
    }}       
])

由于在您没有“聚合”任何内容的情况下使用$unwind通常需要相当大的成本,那么如果您没有其他实用方法可用的现代版本,那么通常最好接受在客户端代码而不是服务器上“过滤”数组内容本身。

因此,对于这种情况,您应该只使用$unwind,这样可以通过删除不匹配项目的顺序“显着”减少数组条目。否则,处理成本可能大于传输数据的网络成本,任何好处都会被否定。

如果您没有现代版本,请获取一个。这些功能与实用和高效的功能完全不同。