单个查询条件需要mongodb $ elemMatch

时间:2017-11-04 16:37:29

标签: mongodb null

我在Mongo(3.4.10)中有一些嵌套数组的文档:

> db.test.find()
{ "a" : [ ] }  // doc number 1
{ "a" : [ { "b" : [ ] } ] }  // doc number 2
{ "a" : [ { "b" : [ { "c" : 1 } ] } ] }  // doc number 3
{ "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] }  // doc number 4
{ "a" : [ { "b" : [ { "c" : 1 } ] }, { "d" : 1 } ] }  // doc number 5
{ "a" : [ {  }, { "b" : 1 } ] }  // doc number 6

我尝试了一些问题,包括$elemMatch和没有:

> db.test.find({'a.b':{$ne:null}})
{ "a" : [ ] }
{ "a" : [ { "b" : [ ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 } ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] }

> db.test.find({a:{$elemMatch:{b:{$ne:null}}}})
{ "a" : [ { "b" : [ ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 } ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 } ] }, { "d" : 1 } ] }
{ "a" : [ {  }, { "b" : 1 } ] }

> db.test.find({'a.b':{$elemMatch:{$ne:null}}})
{ "a" : [ { "b" : [ { "c" : 1 } ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] }
{ "a" : [ { "b" : [ { "c" : 1 } ] }, { "d" : 1 } ] }

docs表示:

  

如果您在<query>表达式中仅指定一个$elemMatch条件,则无需使用$elemMatch

但这些查询都会返回不同的结果。我想知道为什么会这样。我还想知道这些查询究竟选择了什么,因为在尝试和阅读有关数组查询和$elemMatch的文档之后,我无法完成它。

2 个答案:

答案 0 :(得分:1)

第一个查询将返回文档 匹配条件没有b字段:

  

$ ne选择字段值不相等的文档   (即!=)到指定的值。 这包括没有的文件   包含该字段。

在第二个查询中,元素应该在验证条件之前存在。如果没有元素,则不会返回文档:

  

$ elemMatch运算符匹配包含数组字段的文档   至少一个元素与所有指定的查询匹配   标准。

我认为这是$ elemMatch文档中的一个小错误 - 他们应该指出文档中应该存在目标字段以获得完全相同的结果。

答案 1 :(得分:1)

我已经创建了一个测试数据库,这是我对每个输出的逐行说明。

查询1

db.test.find({'a.b':{$ne:null}})

显示:

{ "a" : [ ] } // doesn't contain b, so valid (mentioned by Sergey, see $ne docs)
{ "a" : [ { "b" : [ ] } ] } // has non-null b
{ "a" : [ { "b" : [ { "c" : 1 } ] } ] } // has non-null b
{ "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] } // has non-null b

未显示:

{ "a" : [ {  }, { "b" : 1 } ] } // find({'a.b':null}) matches, so discard
{ "a" : [ { "b" : [ { "c" : 1 } ] }, { "d" : 1 } ] } // find({'a.b':null}) matches, so discard

第一个案例见$ne docs

这两个未显示的文件没有多大意义。它们都有{$ne:null}接受的单个元素,这应该使整个文档被接受。

不幸的是,正如我所担心的那样,Mongo采用简单运行find({'a.b':{$eq:null}})source here)的快捷方式,然后列出所有的项目并将其返回给{{ 1}}。

尝试运行find({'a.b':{$ne:null}})自己查看。这种不幸是基于“不等于”是“相等”的倒数的想法,当单个真实元素使整个文档成立时,这是不正确的(例如find({'a.b':{$not {$eq:null}}})与{{1}不同}})。

查询2

any(x!=3)

显示:

!any(x==3)

未显示:

db.test.find({a:{$elemMatch:{b:{$ne:null}}}})

这里的诀窍是{ "a" : [ { "b" : [ ] } ] } // non-null b { "a" : [ { "b" : [ { "c" : 1 } ] } ] } // non-null b { "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] } // non-null b { "a" : [ { "b" : [ { "c" : 1 } ] }, { "d" : 1 } ] } // one element has non-null b { "a" : [ { }, { "b" : 1 } ] } // one element has non-null b 仅考虑其{ "a" : [ ] } // no elements, $elemMatch needs at least one element that matches $elemMatch此处)为an array of one or more elements的情况。只有这样才会应用谓词。

因此它甚至从未考虑<field>,因为它是一个空数组。在这种情况下,我们看到在所有剩余文档中至少有一个数组a的元素存在非空{ "a" : [ ] }字段,因此接受这些字段。

查询3

b

显示:

a

未显示:

db.test.find({'a.b':{$elemMatch:{$ne:null}}})

这里的诀窍是{ "a" : [ { "b" : [ { "c" : 1 } ] } ] } // a.b an array with 1+ elements { "a" : [ { "b" : [ { "c" : 1 }, { "d" : 1 } ] } ] } // a.b an array with 1+ elements { "a" : [ { "b" : [ { "c" : 1 } ] }, { "d" : 1 } ] } // a.b an array with 1+ elements 仅考虑其{ "a" : [ ] } // a.b not an array with 1+ elements { "a" : [ { "b" : [ ] } ] } // a.b not an array with 1+ elements { "a" : [ { }, { "b" : 1 } ] } // a.b not an array with 1+ elements 是非空数组的情况,但此处$elemMatch<field>而不是<field> }。未显示的三个文档不符合此初始标准,因此从未进行过测试。其余三个文档都是非空数组,超过1个非空元素,所以都被接受了。

结论:

a.b文档确实具有误导性,他们应说明:

  

如果您在a表达式中仅指定一个$elemMatch条件,则只要<query>为非$elemMatch,就不需要使用$elemMatch -empty数组。

即便如此,查询1和3也不一致。这是因为<field>似乎强制$elemMatch每个元素{$ne:null}source here)被评估一次,而排除它似乎将a.b应用于整个{$ne:null}暂时a.b

我认为Mongo应该始终以元素方式应用ne,否则看起来像是一个bug。我已就此提出a Jira Issue in Mongo。请将其投票以解决此问题。