首先说一下 $elemMatch的用法:
{ _id: 1, results: [ 82, 85, 88 ] }
{ _id: 2, results: [ 75, 88, 89 ] }
$elemMatch是匹配document 中数组中至少有一个元素满足$elemMatch中的所有条件,例如:
db.scores.find( { results: { $elemMatch: { $gte: 80, $lt: 85 } } } )
查询结果为:
{ "_id" : 1, "results" : [ 82, 85, 88 ] }
结下来解释一下(Multikey Index Bounds):
在一个查询期间,索引的扫描范围定义了部分索引为了搜索,当多个(条件)predicates 超过一个索引存在时:mongodb 将试图去合并这些(条件)predicates的边界,要么通过求交集的方法合并
要么通过组合的方法,为了去产生一个比较小的扫描范围。给定一个索引数组字段,考虑到在一个查询中,在一个数组中指定了多个(条件)predicates并且可以使用 Multikey Index。
if $elemMatch 中有多个(条件)predicates ,mongodb会合并 Multikey Index的边界。因此,会有$elemMatch是匹配document 中数组中至少有一个元素满足$elemMatch中的所有条件。
继续上面的例子,逐个条件边界的范围:
大于等于80($gte:80)的边界为[80,inf];
小于85($lt:85)的边界为[-inf,85]。
由于使用了$elemMatch组织多个条件查询,mongodb查询的边界为results:[[80,85)]。
我们在来看一下(Compound Bounds for Multikey Index)
由于上面的查询条件可以求交集,但是,假如还有一种情况,有两个数组:
{ _id: 1, results: [ 82, 85, 88 ],scores:[66,77,88] }
{ _id: 2, results: [ 75, 88, 89 ] ,scores:[77,44,22]}
查询条件为:
db.scores.find( { results: { $gte: 85 },scores:{$lt:60}} )
他们是没有交集的,在这种情况下,索引的边界是怎么样的呢?就继续看 Compound Bounds for Multikey Index
把同一个数组中的不同索引键的边界混合在一起的条件如下:
这些索引的keys必须有相同的字段路径,但是不包括字段的names
这个查询必须在指定的字段路径的这个特定的字段上面使用$elemMatch
还是看例子:
{ _id: 1, item: "ABC", ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ] } { _id: 2, item: "XYZ", ratings: [ { score: 5, by: "anon" }, { score: 7, by: "wv" } ] }
创建索引:
db.survey2.createIndex( { "ratings.score": 1, "ratings.by": 1 } )
查询语句:
db.survey2.find( { ratings: { $elemMatch: { score: { $lte: 5 }, by: "anon" } } } )
逐个索引分析:
score {$lte:5}的边界是:[-inf,5],
by {by:"anon"}的边界是:["anon":"anon"]
mongodb 索引混合的结果为:
{ "ratings.score" : [ [ -Infinity, 5 ] ], "ratings.by" : [ [ "anon", "anon" ] ] }
再看一个例子:
{ _id: 1, item: "ABC", ratings: [ { score: { q1: 2, q2: 5 }, certainty: { q1: 2, q2: 3 } }, { score: { q1: 8, q2: 4 }, certainty: { q1: 10, q2: 10 } } ] } { _id: 2, item: "XYZ", ratings: [ { score: { q1: 7, q2: 8 }, certainty: { q1: 5, q2: 5 } }, { score: { q1: 9, q2: 5 }, certainty: { q1: 7, q2: 7 } } ] }
创建的索引为:
db.survey4.createIndex( { "ratings.score.q1": 1, "ratings.score.q2": 1, "ratings.certainty.q1": 1, "ratings.certainty.q2": 1 } )
查询的语句为:
db.survey4.find( { "ratings.score": { $elemMatch: { q1: 5, q2: 5 } }, "ratings.certainty": { $elemMatch: { q1: 7, q2: 7 } }, }
但是,当$elemMatch不能连接"ratings.score"和"ratings.certainty",mongodb 不能混合它们两个的边界,然而,mongodb 强制领导索引字段"ratings.score.q1" 和 "ratings.score.q2"的边界混合。
边界的混合结果如下:
{
"ratings.score.q1" : [ [ 5, 5 ] ],
"ratings.score.q2" : [ [ 5, 5 ] ],
"ratings.certainty.q1" : [ [ MinKey, MaxKey ] ],
"ratings.certainty.q2" : [ [ MinKey, MaxKey ] ]
}