我已经对此进行了一段时间的战斗,而且我似乎无法弄清楚如何执行理论上应该是一个非常简单的查询...
我需要检索(或更确切地说,排除)包含数组的文档,其中两个值都出现在数组中的精确索引处,但是没有一个值出现在该精确索引处。我已经尝试过$ and运算符来实现这一点,但是我没有得到我期望的结果。
数组也可以大于2个值。
我尝试了以下代码,但是所有包含其中一个值在确切位置的文档都将被忽略,而不仅是两个都将被忽略。
$and: [{"value.0": {$ne: 'X'}}, {"value.1": {$ne: 'X'}}]
我希望:
[X,X]
被排除
[Y,X]
将被包含
[X,Y]
将被包含
答案 0 :(得分:1)
是的,这有点棘手,但是您的意思是$or
。
获取您的文档:
{ "value" : [ "X", "X" ] }
{ "value" : [ "X", "X", "A" ] }
{ "value" : [ "Y", "X" ] }
{ "value" : [ "X", "Y" ] }
{ "value" : [ "B", "Y" ] }
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" } }
]
})
但是,前两个位置中存在值不是保证。