根据两个值查找元素

时间:2017-01-26 16:51:00

标签: mongodb mongodb-query

我正在尝试对我的测试集合进行简单的查找

这是一个参赛样本:

{
    "_id": "movie:1",
    "title": "Vertigo",
    "year": 1958,
    "genre": "drama",
    "summary": "Scottie Ferguson, ancien inspecteur de police, est sujet au vertige depuis qu'il a vu mourir son collègue. Elster, son ami, le charge de surveiller sa femme, Madeleine, ayant des tendances suicidaires. Amoureux de la jeune femme Scottie ne remarque pas le piège qui se trame autour de lui et dont il va être la victime... ",
    "country": "DE",
    "director":     {
        "_id": "artist:3",
        "last_name": "Hitchcock",
        "first_name": "Alfred",
        "birth_date": "1899"    
        },
    "actors": [
        {
        "_id": "artist:15",
        "first_name": "James",
        "last_name": "Stewart",
        "birth_date": "1908",
        "role": "John Ferguson" 
        },
        {
        "_id": "artist:16",
        "first_name": "Kim",
        "last_name": "Novak",
        "birth_date": "1925",
        "role": "Madeleine Elster"  
        },
        {
        "_id": "artist:282",
        "first_name": "Arthur",
        "last_name": "Pierre",
        "birth_date": null,
        "role": null    
        }
    ]
}

我想找一部导演也是演员的电影。是否可以使用简单的$ elemMatch来实现:

find({actors: {$elemMatch: {"_id": "this.director._id"} })

谢谢!

2 个答案:

答案 0 :(得分:1)

如果您只需要将导演的ids与演员进行比较,而且只有一位演员可以使用$setIsSubset

db.a.aggregate([
{
    $group : {
        _id : "$_id",
        director_id : {$push : "$director._id"},
        actors_ids : {$first : "$actors._id"}
    }
},
{
    $project : {
        _id : 1,
        directorIsActor : {
            $setIsSubset : ["$director_id", "$actors_ids"]
        }
    }
}
])

答案 1 :(得分:1)

previously linked dupe (possible)开始,使用 $where 的解决方案将会跟随:

db.collection.find({
    "$where": function() {
        self = this;
        return this.actors.filter(function(actor) {
            return self.director._id === actor._id;
        }).length > 0
    }
})

另一种使用聚合框架 $redact 管道的建议方法:

db.collection.aggregate([
    { 
        "$redact": { 
            "$cond": [
                { 
                    "$setIsSubset": [ 
                        ["$director._id"], 
                        {
                            "$map": {
                                "input": "$actors",
                                "as": "el",
                                "in": "$$el._id"
                            }
                        }
                    ] 
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

在上文中, $redact 的条件逻辑是通过使用集合运算符 $setIsSubset {{3 }} 即可。

$map 运算符在将表达式应用于数组中的每个元素后,将返回一个仅包含actors数组中的actor id的数组。例如,表达式

{
    "$map": {
        "input": "$actors",
        "as": "el",
        "in": "$$el._id"
    }
}

如果应用于actors数组

[ 
    {
        "_id" : "artist:3",
        "first_name" : "James",
        "last_name" : "Stewart",
        "birth_date" : "1908",
        "role" : "John Ferguson"
    }, 
    {
        "_id" : "artist:16",
        "first_name" : "Kim",
        "last_name" : "Novak",
        "birth_date" : "1925",
        "role" : "Madeleine Elster"
    }, 
    {
        "_id" : "artist:282",
        "first_name" : "Arthur",
        "last_name" : "Pierre",
        "birth_date" : null,
        "role" : null
    }
]

将返回

[ "artist:3", "artist:16", "artist:282" ]

使用 $map 运算符将此结果与单个元素数组["$directors._id"]进行比较,该运算符采用两个数组,并在第一个数组是第二个数组的子集时返回true,包括当第一个数组等于第二个数组时,否则为false。

例如,

{ 
    "$setIsSubset": [ 
        [ "artist:12" ], 
        [ "artist:3", "artist:16", "artist:282" ] 
    ] 
}       // false

{ 
    $setIsSubset: [ 
        [ "artist:282" ], 
        [ "artist:3", "artist:16", "artist:282" ] 
    ] 
}       // true

然后,运算符的布尔结果将用作 $setIsSubset 管道的基础。

对性能的解释仍然有效: $redact 在必要时是一个很好的黑客,但应尽可能避免。