2017-07-20 110 views
1

如下片段展示三个查询:查询由字段值,在字段阵列不值

  • 找到所有的文件
  • 发现包含含有任一字符串"x"或含有该阵列的字段a的文件串"x"
  • 发现包含含有包含字符串"x"
0阵列的字段 a的文件

我无法找到包含字段a的文档,其中包含字符串"x",不在数组内。

> db.stuff.find({},{_id:0}) 
{ "a" : "x" } 
{ "a" : [ "x" ] } 
> db.stuff.find({a:"x"},{_id:0}) 
{ "a" : "x" } 
{ "a" : [ "x" ] } 
> db.stuff.find({a:{$elemMatch:{$eq:"x"}}},{_id:0}) 
{ "a" : [ "x" ] } 
> 

回答

1

对于“给定路径”中的数据实际上是否在数组中,MongoDB基本上不在乎。如果你想的区别,那么你需要“告诉它”:

db.stuff.find({ "a": "x", "$where": "return !Array.isArray(this.a)" }) 

这是$where增加了讨价还价,在那里你可以提供明确提出了一个条件:“这是一个数组”通过Array.isArray()在JavaScript评估中。而JavaScript NOT !声明颠倒了逻辑。

另一种方法是添加$exists检查:

db.stuff.find({ "a": "x", "a.0": { "$exists": false } }) 

其中也基本上问“这是一个数组”通过寻找该第一元素索引。所以“反向”false大小写意味着“这不是一个数组”。

或者即使你注意,您可以使用$elemMatch只选择阵列,但“否定”,使用$not

db.stuff.find({ "a": { "$not": { "$elemMatch": { "$eq": "x" } } } }) 

虽然可能“而不是”最好的选择,因为这也是“否定索引的使用“,其他例子都通过至少包括”一个“匹配的积极条件来努力避免。因此,它是最好的,包括了“隐AND”组合参数:

db.stuff.find({ 
    "a": { "$eq": "x", "$not": { "$elemMatch": { "$eq": "x" } } } 
}) 

或为“聚合”不支持$where,您可以测试使用$isArray汇聚运营商应该将MongoDB的版本(3.2或更高版本)支持它:

db.stuff.aggregate([ 
    { "$match": { "a": "x" } }, 
    { "$redact": { 
    "$cond": { 
     "if": { "$not": { "$isArray": "$a" } }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }} 
]) 

注意到在任何可能的情况下以及在任何情况下都提供“常规”查询条件是一种很好的做法。

还注意到查询BSON $type通常不会在这种情况下工作,因为该数组本身的“内容”其实都是“字符串”,这是什么$type操作是要考虑的,并因此不报告这样的数组实际上是一个数组。

+0

谢谢!我认为应该在可能的情况下使用'a.0'的答案,因为它会使用索引(如果存在),而'$ where'不能。而且,'return'关键字没用。 – stenci

+0

@stenci这不是“无用的”,它只是“$ where”认为它是“隐含的”,但“良好的语言习惯”(我习惯于这样做)实际上表明你“应该”实际上总是返回'从任何功能。请注意,即使在这种形式下,'function()'也基本上是“隐含的”。 –