MongoDB:在数组中找到两个完全匹配的匹配项

时间:2019-03-17 14:14:56

标签: mongodb

我已经对此进行了一段时间的战斗,而且我似乎无法弄清楚如何执行理论上应该是一个非常简单的查询...

我需要检索(或更确切地说,排除)包含数组的文档,其中两个值都出现在数组中的精确索引处,但是没有一个值出现在该精确索引处。我已经尝试过$ and运算符来实现这一点,但是我没有得到我期望的结果。

数组也可以大于2个值。

我尝试了以下代码,但是所有包含其中一个值在确切位置的文档都将被忽略,而不仅是两个都将被忽略。

$and: [{"value.0": {$ne: 'X'}}, {"value.1": {$ne: 'X'}}]

我希望:

[X,X]被排除

[Y,X]将被包含

[X,Y]将被包含

1 个答案:

答案 0 :(得分:1)

是的,这有点棘手,但是您的意思是$or

获取您的文档:

{ "value" : [ "X", "X" ] }
{ "value" : [ "X", "X", "A" ] }
{ "value" : [ "Y", "X" ] }
{ "value" : [ "X", "Y" ] }
{ "value" : [ "B", "Y" ] }

然后使用$ne运行$or不等式条件:

db.collection.find({ 
  "$or": [
    { "value.0": { "$ne": "X" } },
    { "value.1": { "$ne": "X" } }
  ]
})

返回三个文档:

{ "value" : [ "Y", "X" ] }
{ "value" : [ "X", "Y" ] }
{ "value" : [ "B", "Y" ] }

这是因为必须满足以下条件之一:任一,即"X"不必是这些位置中两个元素的值。当您的逻辑是“这个那个” 时,您实际上是在说$or

请注意,请勿将此与$nor混淆,它是一个声明,所有谓词都不应该匹配“完全”

db.collection.find({ 
  "$nor": [
    { "value.0": "X" },
    { "value.1": "X" }
  ]
})

会返回:

{ "value" : [ "B", "Y" ] }

都不是的位置值中包含"X"

基本上可以归结为两者两者之间的区别


注意

如果您实际上要确保的是“首位” 必须在其中一个元素中包含“ X”,那么您基本上需要一个计算表达式来“切片”数组内容添加到查询逻辑的末尾:

使用$expr$slice,从3.6及更高版本开始使用现代MongoDB

db.collection.find({ 
  "$or": [
    { "value.0": { "$ne": "X" } },
    { "value.1": { "$ne": "X" } }
  ],
  "$expr": {
    "$in": [ "X", { "$slice": [ "$value", 0, 2 ] }]
  }
})

或对于旧版本,通过$where

db.collection.find({ 
  "$or": [
    { "value.0": { "$ne": "X" } },
    { "value.1": { "$ne": "X" } }
  ],
  "$where": function() {
    return this.value.slice(0,2).indexOf("X") != -1
  }
})

两个都只会返回"X"所在的位置:

{ "value" : [ "Y", "X" ] }
{ "value" : [ "X", "Y" ] }

使用常规查询运算符无法表达要查看存在的值的“数组切片”的附加逻辑。因此,使用 additional 语句是为了丢弃在这些位置处所有带有“ X”的任何东西。

请注意,“在技术上” 表达式是必需的,但是此类计算表达式需要进行收集扫描,而常规的 inequality 操作实际上不需要。 / p>

因此,如果您打算这样做,最好将两者结合起来。

“技术上” 只需匹配"X" “可能” 即可:

db.collection.find({ 
  "value": "X",
  "$or": [
    { "value.0": { "$ne": "X" } },
    { "value.1": { "$ne": "X" } }
  ]
})

但是,前两个位置中存在值不是保证