MongoDB查询:匹配文档数组中的每个元素到条件。

7
我有类似这样的文档:
{_id: 1, values : [2,3,4] }
{_id: 2, values: [4] }
{_id: 3, values : [3,4,5,6,7,8,9,10,11] }
每个文档都有一个数组。我需要一个查询,只有在其数组的每个元素与所需条件匹配时才返回文档(而不是任何元素匹配时)。
例如。类似于以下内容(但并非如此)
{ 'values' : { '$gt' : 1, '$lt': 5} }
如果第一个和第二个文档都会成功返回,但不会返回第三个文档,因为第三个文档的数组“values”的所有元素都不符合条件。
显然,MongoDB在数组查询中使用隐式OR,而我需要AND。
我猜我可以手动索引每个元素,例如:
collection.find({values.0: {$gt:1,$lt:5}, values.1:{$gt:1,$lt:5}, ... values.n:{$gt:1,$lt:5}}),但我的数组高度动态,这很麻烦。
是否有更好的方法?
注意:我在mongodb-user上提出了这个问题,但由于对$all运算符不熟悉而引起混乱。在这里,我关心的是文档数组,而不是查询数组。此外,在这种数字情况下,我意识到可能会编写否定所需范围的查询,但通常我将无法编写否定。

你的问题已经在24小时前在MongoDB列表上得到了回答。 - user2665694
很奇怪,因为我今天刚写的。它被那边的AJ搞混了——与$all运算符无关。 - ricopan
5个回答

8
我认为目前还没有其他方法,除了手动迭代文档并检查数组中的每个值。这将相当缓慢,因为它必须在每个文档上执行JavaScript,并且不能利用col.values索引。
即使是$where JavaScript表达式查询似乎也无法在此处工作,可能是因为查询包含回调并且过于复杂。
db.col.find("this.values.every(function(v) { return (v > 1 && v < 5) })")

编辑: 对于某些查询,包括这个查询,在 JavaScript 的 $where 表达式中需要一个 return 语句才能正常工作:

db.col.find("return this.values.every(function(v) { return (v > 1 && v < 5) })")

我已经测试过它并且对我有效。对于我的应用程序来说,这可能是最好的解决方案——虽然它可能会慢一些,但否则我将不得不在客户端迭代文档。这是使用JS表达式的良好入门。已投票并接受。 - ricopan

6
MongoDB,像大多数(如果不是全部)数据库一样,只实现了存在量词(∃,存在)及其否定形式(∄,不存在)。它没有全称量词(∀,对于所有)及其否定形式,因为它们无法使用索引进行优化,并且在实践中没有用处。幸运的是,在一阶逻辑中,涉及∀的每个语句都可以转换为涉及∃的等价语句。
在您的示例中,语句:
“所有值都> 1且< 5”
等同于
“不存在x∈值:¬(x> 1 ∧ x <5)”。

或者说,“没有一个值是不大于1且小于5的”,根据德摩根定律,可以转化为:

∄ x ∈ values : x ≤ 1 ∨ x ≥ 5

或者说,“没有一个值是小于等于1或大于等于5的”。

后者可以用多种方式在MongoDB中表达,例如:

> db.test.remove()
> db.test.insert({_id: 1, values: [2, 3, 4]})
> db.test.insert({_id: 2, values: [4]})
> db.test.insert({_id: 3, values: [3, 4, 5, 6, 7, 8, 9, 10, 11]})

> db.test.find({$nor: [{values: {$lte: 1}}, {values: {$gte: 5}}]})
{ "_id" : 1, "values" : [  2,  3,  4 ] }
{ "_id" : 2, "values" : [  4 ] }

2

你可能会牺牲速度,但是你可以使用JavaScript表达式,直接传递给find()或者$where

你可以循环遍历数组中的元素,并且只有当它们都满足条件时才返回true。


谢谢。我会尝试上面cxfx提供的JavaScript代码。我已经为你投了赞,但不幸的是,某个声望较高的管理员将其撤销了。 - ricopan

0

据我所知,目前使用MongoDB是不可能实现这个的。

编辑:我错了。它是可以实现的,只是不能索引,所以对我来说属于“不可能”的范畴。请参见下面的位置。您还可以进行映射减少操作。这些就像MongoDB中的“出狱卡”,但通常情况下,与真正的运算符相比,存在严重的缺点。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接