%lt%gt 作用在数组字段上

{"x" : 5}
{"x" : 15}
{"x" : 25}
{"x" : [5, 25]}
{"x" : [5, 7]}
> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}})
{"x" : 15}
{"x" : [5, 25]}

文档中的标量(非数组元素)必须与查询条件中的每一条子句相匹配。如果使用 {"x" : {"$gt" : 10, "$lt" : 20}} 进行查询,那么 "x" 必须同时满足大于 10 且小于 20。然而,如果文档中的 "x" 字段是一个数组,那么当 "x" 键的某一个元素与查询条件的任意一条语句相匹配(查询条件中的每条语句可以匹配不同的数组元素)时,此文档也会被返回。


MongoDB 的这个行为是由它在「数组元素」与「范围型查询」之间的交互方式决定的。

一句话:数组的 每一个元素 都会分别与 $gt / $lt 比较,只要有 任意一个元素 落在范围里,整份文档就会被认为满足条件。


把例子拆开来看

集合里有 4 条文档:

{ x: 5 }          // 标量
{ x: 15 }         // 标量
{ x: 25 }         // 标量
{ x: [5, 25] }    // 数组

查询条件:

{ x: { $gt: 10, $lt: 20 } }

MongoDB 的处理步骤:

  1. 标量 字段

    直接拿 x 的值去比较:

  2. 数组 字段 { x: [5, 25] }

    MongoDB 会把数组里的 每个元素 都拿出来单独比较:

    然而关键点在于 “范围查询的语义”

    这两个条件并没有要求 同一个元素 同时满足两边,只要数组里「存在某个元素 > 10」并且「存在某个元素 < 20」,就会被认为整个条件成立。

    [5, 25] 里:

    于是文档 { x: [5, 25] } 被判定为符合条件。


如何避免这种“跨元素匹配”?

如果希望 同一个数组元素 必须同时满足上下界,需要用 $elemMatch 把条件绑定到单个元素上:

db.test.find({ x: { $elemMatch: { $gt: 10, $lt: 20 } } })